package com.dungeon.game;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.graphics.Color;

import com.dungeon.game.Constants.Action_color_code;
import com.dungeon.game.Constants.Character_action_code;
import com.dungeon.game.Constants.Monster_action_code;
import com.dungeon.game.Constants.Monster_code;
import com.dungeon.game.Constants.Position_code;
import com.dungeon.game.Constants.Potion_type;
import com.dungeon.game.Constants.Stance_code;
import com.dungeon.game.Constants.Status_effect_code;
import com.dungeon.game.Enemies.Mob;
import com.dungeon.game.Party.Character;

public class Character_action_factory {
	Character_action make_action(Character_action_code ac){
	    if (ac==Character_action_code.CA_DEFLECT){
	        return new Deflect_CA();}
	    else if (ac==Character_action_code.CA_SMITE){
	        return new Smite_CA();}
	    else if (ac==Character_action_code.CA_LEADER){
	        return new Leader_CA();}
	    else if (ac==Character_action_code.CA_RETRENCH){
	        return new Retrench_CA();}
	    else if (ac==Character_action_code.CA_CLEAVE){
	        return new Cleave_CA();}
	    else if (ac==Character_action_code.CA_BLOCK){
	        return new Block_CA();}
	    else if (ac==Character_action_code.CA_BASH){
	        return new Bash_CA();}
	    else if (ac==Character_action_code.CA_SWIPE){
	        return new Swipe_CA();}
	    else if (ac==Character_action_code.CA_RUTHLESS){
	        return new Ruthless_CA();}
	    else if (ac==Character_action_code.CA_THROW){
	        return new Throw_CA();}
	    else if (ac==Character_action_code.CA_POISON_RESISTANCE){
	        return new PoisonResistance_CA();}
	    else if (ac==Character_action_code.CA_FIRE_RESISTANCE){
	        return new FireResistance_CA();}
	    else if (ac==Character_action_code.CA_AGGRESSIVE){
	        return new Aggressive_CA();}
	    else if (ac==Character_action_code.CA_TAUNT){
	        return new Taunt_CA();}
	    else if (ac==Character_action_code.CA_BEACON){
	        return new Beacon_CA();}
	    else if (ac==Character_action_code.CA_DRAGON_SLAYER){
	        return new DragonSlayer_CA();}
	    else if (ac==Character_action_code.CA_DEATHBLOW){
	        return new Deathblow_CA();}
	    else if (ac==Character_action_code.CA_RESIST_FIRE){
	        return new ResistFire_CA();}
	    else if (ac==Character_action_code.CA_SACRIFICE){
	        return new Sacrifice_CA();}
	    else if (ac==Character_action_code.CA_HEALING){
	        return new Healing_CA();}
	    else if (ac==Character_action_code.CA_SELF_HEAL){
	        return new SelfHeal_CA();}
	    else if (ac==Character_action_code.CA_SMALL_HEAL){
	        return new SmallHeal_CA();}
	    else if (ac==Character_action_code.CA_BIG_HEAL){
	        return new BigHeal_CA();}
	    else if (ac==Character_action_code.CA_MASS_HEAL){
	        return new MassHeal_CA();}
	    else if (ac==Character_action_code.CA_CURE_POISON){
	        return new CurePoison_CA();}
	    else if (ac==Character_action_code.CA_ROSARY){
	        return new Rosary_CA();}
	    else if (ac==Character_action_code.CA_AGGRO){
	        return new Aggro_CA();}
	    else if (ac==Character_action_code.CA_ARMOR){
	        return new Armor_CA();}
	    else if (ac==Character_action_code.CA_CONCENTRATION){
	        return new Concentration_CA();}
	    else if (ac==Character_action_code.CA_HEALER){
	        return new Healer_CA();}
	    else if (ac==Character_action_code.CA_RIGHTEOUSNESS){
	        return new Righteousness_CA();}
	    else if (ac==Character_action_code.CA_LUCKY_ESCAPE){
	        return new LuckyEscape_CA();}
	    else if (ac==Character_action_code.CA_DODGE){
	        return new Dodge_CA();}
	    else if (ac==Character_action_code.CA_SNIPE){
	        return new Snipe_CA();}
	    else if (ac==Character_action_code.CA_TAKE_COVER){
	        return new TakeCover_CA();}
	    else if (ac==Character_action_code.CA_LUCKY_SHOT){
	        return new LuckyShot_CA();}
	    else if (ac==Character_action_code.CA_FIND_WEAKNESS){
	        return new FindWeakness_CA();}
	    else if (ac==Character_action_code.CA_FIND_TRAPS){
	        return new FindTraps_CA();}
	    else if (ac==Character_action_code.CA_INSULT_YOUR_MOTHER){
	        return new InsultYourMother_CA();}
	    else if (ac==Character_action_code.CA_ASSASSIN){
	        return new Assassin_CA();}
	    else if (ac==Character_action_code.CA_ARCHER){
	        return new Archer_CA();}
	    else if (ac==Character_action_code.CA_RIPOSTE){
	        return new Riposte_CA();}
	    else if (ac==Character_action_code.CA_PENETRATION){
	        return new Penetration_CA();}
	    else if (ac==Character_action_code.CA_MORE_GOLD){
	        return new MoreGold_CA();}
	    else if (ac==Character_action_code.CA_MORE_GEMS){
	        return new MoreGems_CA();}
	    else if (ac==Character_action_code.CA_PICK_LOCKS){
	        return new PickLocks_CA();}
	    else if (ac==Character_action_code.CA_INCONSPICUOUS){
	        return new Inconspicuous_CA();}
	    else if (ac==Character_action_code.CA_POISON_CLOUD){
	        return new PoisonousCloud_CA();}
	    else if (ac==Character_action_code.CA_COUNTERSPELL_PARALYSIS){
	        return new CounterspellParalysis_CA();}
	    else if (ac==Character_action_code.CA_LIGHTNING_BOLT){
	        return new LightningBolt_CA();}
	    else if (ac==Character_action_code.CA_FRONT_ROW_BUFF){
	        return new FrontRowBuff_CA();}
	    else if (ac==Character_action_code.CA_CLEANSING_FLAME){
	        return new CleansingFlame_CA();}
	    else if (ac==Character_action_code.CA_REVEAL_DANGER){
	        return new RevealDanger_CA();}
	    else if (ac==Character_action_code.CA_ALL_OUT_DEFENSE){
	        return new AllOutDefense_CA();}
	    else if (ac==Character_action_code.CA_REVITALISE){
	        return new Revitalise_CA();}
	    else if (ac==Character_action_code.CA_STEALTH){
	        return new Stealth_CA();}
	    else if (ac==Character_action_code.CA_CLOAK_OF_SHADOWS){
	        return new CloakOfShadows_CA();}
	    else if (ac==Character_action_code.CA_FLY){
	        return new Fly_CA();}
	    else if (ac==Character_action_code.CA_BERSERK){
	        return new Berserk_CA();}
	    else if (ac==Character_action_code.CA_AMBUSH){
	        return new Ambush_CA();}
	    else if (ac==Character_action_code.CA_WAND_LORE){
	        return new WandLore_CA();}
	    else if (ac==Character_action_code.CA_WAND_LORE_2){
	        return new WandLore2_CA();}
	    else if (ac==Character_action_code.CA_BUFF_EV){
	        return new BuffEV_CA();}
	    else if (ac==Character_action_code.CA_FORCE_BRAND){
	        return new ForceBrand_CA();}
	    else if (ac==Character_action_code.CA_SHIELD){
	        return new Shield_CA();}
	    else if (ac==Character_action_code.CA_INVULNERABILITY){
	        return new Invulnerability_CA();}
	    else if (ac==Character_action_code.CA_DEFLECT_MISSILE){
	        return new DeflectMissile_CA();}
	    else if (ac==Character_action_code.CA_POISON_CLOUD_2){
	        return new PoisonCloud2_CA();}
	    else if (ac==Character_action_code.CA_SPARK){
	        return new Spark_CA();}
	    else if (ac==Character_action_code.CA_FIREBOLT){
	        return new Firebolt_CA();}
	    else if (ac==Character_action_code.CA_MISSILE){
	        return new Missile_CA();}
	    else if (ac==Character_action_code.CA_ESCAPE){
	        return new Escape_CA();}
	    else if (ac==Character_action_code.CA_KNIT_FLESH){
	        return new KnitFlesh_CA();}
	    else if (ac==Character_action_code.CA_BLOOD_MAGIC){
	        return new BloodMagic_CA();}
	    else if (ac==Character_action_code.CA_STICKY_FLAMES){
	        return new StickyFlames_CA();}
	    else if (ac==Character_action_code.CA_SHOCKING_GRASP){
	        return new ShockingGrasp_CA();}
	    else if (ac==Character_action_code.CA_WEAKEN){
	        return new Weaken_CA();}
	    else if (ac==Character_action_code.CA_ACCURATE_SHOT){
	        return new AccurateShot_CA();}
	    else if (ac==Character_action_code.CA_STEELY_GAZE){
	        return new SteelyGaze_CA();}
	    else if (ac==Character_action_code.CA_RESIST_FEAR){
	        return new ResistFear_CA();}
	    else if (ac==Character_action_code.CA_KNOCKBACK){
	        return new Knockback_CA();}
	    else if (ac==Character_action_code.CA_VETERAN){
	        return new Veteran_CA();}
	    else if (ac==Character_action_code.CA_PROTECT_THE_FALLEN){
	        return new ProtectTheFallen_CA();}
	    else if (ac==Character_action_code.CA_STUNNING_BLOW){
	        return new StunningBlow_CA();}
	    else if (ac==Character_action_code.CA_RAGE){
	        return new Rage_CA();}
	    else if (ac==Character_action_code.CA_CURE_FEAR){
	        return new CureFear_CA();}
	    else if (ac==Character_action_code.CA_UNDEAD_SLAYER){
	        return new UndeadSlayer_CA();}
	    else if (ac==Character_action_code.CA_TURN_UNDEAD){
	        return new TurnUndead_CA();}
	    else if (ac==Character_action_code.CA_MEDITATION){
	        return new Meditation_CA();}
	    else if (ac==Character_action_code.CA_CURE_MORTAL_WOUNDS){
	        return new CureMortalWounds_CA();}
	    else if (ac==Character_action_code.CA_CURSE){
	        return new Curse_CA();}
	    else if (ac==Character_action_code.CA_MAGEBANE){
	        return new Magebane_CA();}
	    else if (ac==Character_action_code.CA_VENDETTA){
	        return new Vendetta_CA();}
	    else if (ac==Character_action_code.CA_CONFUSING_SPIEL){
	        return new ConfusingSpiel_CA();}
	    else if (ac==Character_action_code.CA_FREE_ACTION){
	        return new FreeAction_CA();}
	    else if (ac==Character_action_code.CA_DISTRACTION){
	        return new Distraction_CA();}
	    else if (ac==Character_action_code.CA_CONFUSION){
	        return new Confusion_CA();}
	    else if (ac==Character_action_code.CA_DECONSTRUCT){
	        return new Deconstruct_CA();}
	    else if (ac==Character_action_code.CA_COUNTER_FEAR){
	        return new CounterFear_CA();}
	    else if (ac==Character_action_code.CA_COUNTER_SLEEP){
	        return new CounterSleep_CA();}
	    else if (ac==Character_action_code.CA_COUNTER_SILENCE){
	        return new CounterSilence_CA();}
	    else if (ac==Character_action_code.CA_REFLECTION){
	        return new Reflection_CA();}
	    else if (ac==Character_action_code.CA_EXTINGUISH){
	        return new Extinguish_CA();}
	    else if (ac==Character_action_code.CA_SLOW_TIME){
	        return new SlowTime_CA();}
	    else if (ac==Character_action_code.CA_QUICK_THINKING){
	        return new QuickThinking_CA();}
	    else if (ac==Character_action_code.CA_SHOCKWAVE){
	        return new Shockwave_CA();}
	    else if (ac==Character_action_code.CA_DISPELL){
	        return new Dispell_CA();}
	    else if (ac==Character_action_code.CA_EPIC_BLOCK){
	        return new Epic_Block_CA();}
	    else if (ac==Character_action_code.CA_LEAP_ASIDE){
	        return new Leap_Aside_CA();}
	    else if (ac==Character_action_code.CA_GRAVE_ROBBER){
	        return new GraveRobber_CA();}
	    else if (ac==Character_action_code.CA_QUICK_EXIT){
	        return new QuickExit_CA();}
	    else if (ac==Character_action_code.CA_SHOOT){
	        return new Shoot_NeverUsed_CA();}
	    else if (ac==Character_action_code.CA_SLING){
	        return new Sling_NeverUsed_CA();}
	    else if (ac==Character_action_code.CA_ZEAL) return new Zeal_CA();
	    else if (ac==Character_action_code.CA_WRATHFUL) return new Wrathful_CA();
	    else if (ac==Character_action_code.CA_POLEARM_STRIKE) return new Polearm_strike_CA();
	    else if (ac==Character_action_code.CA_FLURRY) return new Flurry_CA();
	    else if (ac==Character_action_code.CA_COUNTER_DRAINING) return new Counter_draining_CA();
	    else if (ac==Character_action_code.CA_LIGHT) return new Light_CA();
	    else if (ac==Character_action_code.CA_ARROW_CUTTING) return new Arrow_cutting_CA();
	    else if (ac==Character_action_code.CA_DEADLY_BLADE) return new Deadly_blade_CA();
	    else if (ac==Character_action_code.CA_LOB) return new Lob_CA();
	    else if (ac==Character_action_code.CA_WARRIOR_SNIPE) return new Warrior_snipe_CA();
	    else if (ac==Character_action_code.CA_JUST_A_SCRATCH) return new Just_a_scratch_CA();
	    else if (ac==Character_action_code.CA_SALVATION) return new Salvation_CA();
	    else if (ac==Character_action_code.CA_SAVING_THROW) return new Saving_throw_CA();
	    else if (ac==Character_action_code.CA_ETERNAL_FLAME) return new Eternal_flame_CA();
	    else if (ac==Character_action_code.CA_ZEN_ARCHER) return new Zen_archer_CA();
	    else if (ac==Character_action_code.CA_FIRE_IMMUNITY) return new Fire_immunity_CA();
	    else if (ac==Character_action_code.CA_FROST_BOLT) return new Frost_bolt_CA();
	    else if (ac==Character_action_code.CA_POISON_BOLT) return new Poison_bolt_CA();
	    else if (ac==Character_action_code.CA_RAY_OF_LIGHT) return new Ray_of_light_CA();
	    else if (ac==Character_action_code.CA_HOLY_LIGHT) return new Holy_light_CA();
	    else if (ac==Character_action_code.CA_COLD_RESISTANCE) return new Cold_resistance_CA();
	    else if (ac==Character_action_code.CA_RESIST_DRAINING) return new Resist_draining_CA();
	    else if (ac==Character_action_code.CA_WATCHFUL) return new Watchful_CA();
	    else if (ac==Character_action_code.CA_INSOLENT) return new Insolent_CA();
	    else if (ac==Character_action_code.CA_HUNTER) return new Hunter_CA();
	    else if (ac==Character_action_code.CA_TIRELESS) return new Tireless_CA();
	    else if (ac==Character_action_code.CA_PRECOCIOUS) return new Precocious_CA();
	    else if (ac==Character_action_code.CA_TEACHER) return new Teacher_CA();
	    else if (ac==Character_action_code.CA_PACKRAT) return new Packrat_CA();
	    else if (ac==Character_action_code.CA_APOTHECARY) return new Apothecary_CA();
	    else if (ac==Character_action_code.CA_FAST_CAST) return new Fast_cast_CA();
	    else if (ac==Character_action_code.CA_EVASIVE) return new Evasive_CA();
	    else if (ac==Character_action_code.CA_RECUPERATE) return new Recuperate_CA();
	    else if (ac==Character_action_code.CA_TOUGH) return new Tough_CA();
	    else if (ac==Character_action_code.CA_FAST_LEARNER) return new Fast_learner_CA();
	    else if (ac==Character_action_code.CA_SANCTUARY) return new Sanctuary_CA();
	    else if (ac==Character_action_code.CA_GUIDANCE) return new Guidance_CA();
	    else if (ac==Character_action_code.CA_BATTLECRY) return new Battlecry_CA();
	    else if (ac==Character_action_code.CA_ON_YOUR_GUARD) return new On_your_guard_CA();
	    else if (ac==Character_action_code.CA_HAIL_OF_ARROWS) return new Hail_of_arrows_CA();
	    else if (ac==Character_action_code.CA_RECKLESS) return new Reckless_CA();
	    else if (ac==Character_action_code.CA_BLESSING) return new Blessing_CA();
	    else if (ac==Character_action_code.CA_BE_WATCHFUL) return new Be_watchful_CA();
	    else if (ac==Character_action_code.CA_ICE_STORM) return new Ice_storm_CA();
	    else if (ac==Character_action_code.CA_CHAIN_LIGHTNING) return new Chain_lightning_CA();
	    else if (ac==Character_action_code.CA_FIREBALL) return new Fireball_CA();
	    else if (ac==Character_action_code.CA_DEATH_SPELL) return new Death_spell_CA();
	    else if (ac==Character_action_code.CA_EXTERMINATE) return new Exterminate_CA();
	    else if (ac==Character_action_code.CA_DISPEL_SUMMONS) return new Dispel_summons_CA();
	    else if (ac==Character_action_code.CA_DISPEL_UNDEAD) return new Dispel_undead_CA();
	    else if (ac==Character_action_code.CA_TELEPORT_AWAY) return new Teleport_away_CA();
	    else if (ac==Character_action_code.CA_BEFRIEND_ANIMAL) return new Befriend_animal_CA();
	    else if (ac==Character_action_code.CA_ANIMAL_KINSHIP) return new Animal_kinship_CA();
	    else if (ac==Character_action_code.CA_FIRST_AID) return new First_aid_CA();
	    else if (ac==Character_action_code.CA_BRIBE) return new Bribe_CA();
	    else if (ac==Character_action_code.CA_COUP_DE_GRACE) return new Finishing_blow_CA();
	    else if (ac==Character_action_code.CA_REBUKE) return new Rebuke_CA();
	    else if (ac==Character_action_code.CA_SHORTEN_THE_TALE) return new Shorten_the_tale_CA();
	    else if (ac==Character_action_code.CA_DETECT_MAGIC) return new Detect_magic_CA();
	    else if (ac==Character_action_code.CA_DEATH_TOUCH) return new Death_touch_CA();
	    else if (ac==Character_action_code.CA_MASS_CONFUSION) return new Mass_confusion_CA();
	    else if (ac==Character_action_code.CA_RIDDLE) return new Riddle_CA();
	    else if (ac==Character_action_code.CA_SUMMON_FRIEND) return new Summon_friend_CA();
	    else if (ac==Character_action_code.CA_LIFE_LEECH) return new Life_leech_CA();
	    else if (ac==Character_action_code.CA_LAY_ON_HANDS) return new Lay_on_hands_CA();
	    else if (ac==Character_action_code.CA_FAST_CAST_FRONT_ROW) return new Fast_cast_front_row_CA();
	    else if (ac==Character_action_code.CA_STUN_RESISTANCE) return new Stun_resistance_CA();
	    else if (ac==Character_action_code.CA_FEAR) return new Fear_CA();
	    else if (ac==Character_action_code.CA_DISBELIEVE) return new Disbelieve_CA();
	    else if (ac==Character_action_code.CA_KNOCK) return new Knock_CA();
	    else if (ac==Character_action_code.CA_BASH_DOOR) return new Bash_door_CA();
	    else if (ac==Character_action_code.CA_CATCH_BOULDER) return new Catch_boulder_CA();
	    else if (ac==Character_action_code.CA_FAST) return new Fast_CA();
	    else if (ac==Character_action_code.CA_INOFFENSIVE) return new Inoffensive_CA();
	    else if (ac==Character_action_code.CA_BRUTAL) return new Brutal_CA();
	    else if (ac==Character_action_code.CA_DEFT) return new Deft_CA();
	    else if (ac==Character_action_code.CA_AGILE) return new Agile_CA();
	    else if (ac==Character_action_code.CA_KEEN) return new Keen_CA();
	    else if (ac==Character_action_code.CA_ROBUST) return new Robust_CA();
	    else if (ac==Character_action_code.CA_CAPTAIN) return new Captain_CA();
	    else if (ac==Character_action_code.CA_KNIGHT) return new Knight_CA();
	    else if (ac==Character_action_code.CA_BARBARIAN) return new Barbarian_CA();
	    else if (ac==Character_action_code.CA_RANGER) return new Ranger_CA();
	    else if (ac==Character_action_code.CA_BURGLAR) return new Burglar_CA();
	    else if (ac==Character_action_code.CA_THIEF) return new Thief_CA();
	    else if (ac==Character_action_code.CA_SWASHBUCKLER) return new Swashbuckler_CA();
	    else if (ac==Character_action_code.CA_MARKSMAN) return new Marksman_CA();
	    else if (ac==Character_action_code.CA_WARLOCK) return new Warlock_CA();
	    else if (ac==Character_action_code.CA_THAUMATURGE) return new Thaumaturge_CA();
	    else if (ac==Character_action_code.CA_ENCHANTER) return new Enchanter_CA();
	    else if (ac==Character_action_code.CA_SHAMAN) return new Shaman_CA();
	    else if (ac==Character_action_code.CA_PALADIN) return new Paladin_CA();
	    else if (ac==Character_action_code.CA_TEMPLAR) return new Templar_CA();
	    else if (ac==Character_action_code.CA_MEDIC) return new Medic_CA();
	    else if (ac==Character_action_code.CA_PADRE) return new Padre_CA();
	    else if (ac==Character_action_code.CA_DELAYED_BLAST) return new Delayed_blast_CA();
	    else if (ac==Character_action_code.CA_RESIST_LIGHTNING) return new Lightning_resistance_CA();
	    else if (ac==Character_action_code.CA_PROTECT_FROM_COLD) return new Protection_from_cold_CA();
	    else if (ac==Character_action_code.CA_CHALICE) return new Chalice_CA();
	    else if (ac==Character_action_code.CA_SELF_SACRIFICE) return new Self_sacrifice_CA();
	    else if (ac==Character_action_code.CA_SUPER_SMITE) return new Super_smite_CA();
	    else if (ac==Character_action_code.CA_THEURGIC_WAVE) return new Theurgic_wave_CA();
	    else if (ac==Character_action_code.CA_SNEAKY) return new Sneaky_CA();
	    else if (ac==Character_action_code.CA_LETHAL) return new Lethal_CA();
	    else if (ac==Character_action_code.CA_LIFT_SKIRTS) return new Lift_skirts_CA();
	    else if (ac==Character_action_code.CA_UNCEASING_FIRE) return new Unceasing_fire_CA();
	    else if (ac==Character_action_code.CA_SPOTTER) return new Spotter_CA();
	    else if (ac==Character_action_code.CA_MOCKERY) return new Mockery_CA();
	    else if (ac==Character_action_code.CA_UNDAUNTED) return new Undaunted_CA();
	    else if (ac==Character_action_code.CA_SLOW) return new Slow_CA();
	    else if (ac==Character_action_code.CA_PHYSICAL_RESISTANCE) return new Physical_resistance_CA();
	    else if (ac==Character_action_code.CA_HAGGLER) return new Haggler_CA();
   		else if (ac==Character_action_code.CA_INSPIRING) return new Inspiring_CA();
   		else if (ac==Character_action_code.CA_CAROUSE) return new Carouse_CA();
   		else if (ac==Character_action_code.CA_ADVERSITY) return new Adversity_CA();
	    else if (ac==Character_action_code.CA_POT_SMALLHEAL){
	        return new PotSmallheal_CA(1);}
	    else if (ac==Character_action_code.CA_POT_MEDHEAL){
	        return new PotMedheal_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BIGHEAL){
	        return new PotBigheal_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BARPRIEST){
	        return new PotBarpriest_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BARMAGE){
	        return new PotBarmage_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BARROGUE){
	        return new PotBarrogue_CA(1);}
	    else if (ac==Character_action_code.CA_POT_PERCENTHEAL){
	        return new PotPercentheal_CA(1);}
	    else if (ac==Character_action_code.CA_POT_ANTIDOTE){
	    	return new PotAntidote_CA(1);}
	    else if (ac==Character_action_code.CA_POT_FIRERESIST){
	    	return new PotFireresist_CA(1);}
	    else if (ac==Character_action_code.CA_POT_COLDRESIST){
	    	return new PotColdresist_CA(1);}
	    else if (ac==Character_action_code.CA_POT_INVULNERABILITY){
	    	return new PotInvulnerability_CA(1);}
	    else if (ac==Character_action_code.CA_POT_COURAGE){
	    	return new PotCourage_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BERSERK){
	    	return new PotBerserk_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BOOM){
	    	return new PotBoom_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BAR){
	    	return new PotBar_CA(1);}
	    else if (ac==Character_action_code.CA_POT_BALM){
	    	return new PotBalm_CA(1);}
	    else if (ac==Character_action_code.CA_POT_PHILTRE){
	    	return new PotPhiltre_CA(1);}
	    return null;
	}
}

class Character_action implements Serializable {

	Character c;
	Character_action_code action_code;
	Double last_used;
	Integer limited_uses;
	Mob mob_target;
	Character char_target;
	Potion_type potion_code;

	public Character_action(){
        last_used = null;
        limited_uses = null;
        potion_code = null;
	}

    String name(){
        return "";
    }

    String message(){
        return "";
    }

    boolean callable(){
        return true;
    }

    boolean target_friend(){
        return false;
    }

    boolean target_enemy(){
        return false;
    }

    boolean enemy_target_back_row_ok(){
        return true; // but usually suppressed by target_enemy=false;
    }

    boolean enemy_target_front_row_ok(){
        return true; // but usually suppressed by target_enemy=false;
    }

    int reflex_level(){
        return 1;
    }

    double delay(){
        return 0.0;
    }

    double get_delay(){
    	for (Character_action ca : c.actions){
    		if (ca.action_code==Character_action_code.CA_SHAMAN)
    			return delay()*0.8;
    		if (ca.action_code==Character_action_code.CA_FAST_CAST)
    			return delay()*0.5;
    		if (ca.action_code==Character_action_code.CA_FAST_CAST_FRONT_ROW && c.front_row())
    			return delay()*0.5;
    	}
    	return delay();
    }

    Double cooldown(){
        return null;
    }

    Double get_cooldown(){
    	if (cooldown()==null) return null;
    	for (Character_action ca : c.actions){
    		if (ca.action_code==Character_action_code.CA_TIRELESS)
    			return cooldown()*0.5;
    	}
    	return cooldown();
    }

    boolean disruptable(){
        return false;
    }

    int cost(){
        if (base_cost()>0){
            return (int)Math.max(1,Math.floor(base_cost() * cost_mult(c.stamina)));
        } else {
            return 0;
        }
    }

    int base_cost(){
        return 0;
    }

    boolean back_row_ok(){
        return true;
    }

    boolean front_row_ok(){
        return true;
    }

    boolean char_is_aggressive(){
        for (Character_action action : c.actions)
            if (action.action_code == Character_action_code.CA_AGGRESSIVE || action.action_code == Character_action_code.CA_UNCEASING_FIRE || action.action_code == Character_action_code.CA_ZEAL || action.action_code == Character_action_code.CA_WRATHFUL)
                return true;
        return false;
    }

    boolean needed(){
        return false; // default is never carried out by reflex;
    }

    void set_reflex_target(){
    	// stub
    }

    boolean ok(){
    	if (c.pos==null) return false;
        if (!callable())
            return false;
        if (c.front_row() && !front_row_ok())
            return false;
        if (!c.front_row() && !back_row_ok())
            return false;
        if (target_enemy() && mob_valid_targets().size()==0)
            return false;
        if (target_friend() && char_valid_targets().size()==0)
            return false;
        if (get_cooldown()!=null && last_used!=null && last_used+get_cooldown()>Gamestate.w.clock)
            return false;
        if (c.energy<cost())
            return false;
        if (limited_uses!=null && limited_uses==0)
            return false;
        if (c.current_stance==Stance_code.ST_BERSERK && !berserkable())
            return false;
        if (c.has_status_effect(Status_effect_code.EF_GRAPPLE))
            return false;
        if (c.has_status_effect(Status_effect_code.EF_PETRIFY))
            return false;
        if (disruptable() && c.has_status_effect(Status_effect_code.EF_FEAR))
            return false;
        if (Gamestate.w.silence_until > Gamestate.w.clock && disruptable())
            return false;
        return true;
    }

    boolean berserkable(){
    	return false;
    }

    boolean enemy_target_ok(Mob m){
        if (m.front_row() && !enemy_target_front_row_ok())
            return false;
        if (!m.front_row() && !enemy_target_back_row_ok())
            return false;
        if (!m.alive)
            return false;
        if (m.about_to_die)
            return false;
        return true;
    }

    boolean friend_target_ok(Character cc){
        if (cc.number==c.number)
            return false;
        if (!cc.alive)
            return false;
        if (cc.about_to_die)
            return false;
        if (cc.has_status_effect(Status_effect_code.EF_PETRIFY))
        	return false;
        return true;
    }

    List<Character> char_valid_targets(){
        if (target_friend()){
            ArrayList<Character> targets = new ArrayList<Character>();
            for (Character cc : Gamestate.p.chars){
                if (friend_target_ok(cc))
                    targets.add(cc);
            }
            return targets;
        } else {
        	return new ArrayList<Character>();
        }
    }

    List<Mob> mob_valid_targets(){
        if (target_enemy()){
            ArrayList<Mob> targets = new ArrayList<Mob>();
            // want to sort the options nicely by position;
            for (Position_code pos : Arrays.asList(Position_code.POS_M_FRONT_1,Position_code.POS_M_FRONT_2,Position_code.POS_M_FRONT_3,Position_code.POS_M_BACK_1,Position_code.POS_M_BACK_2,Position_code.POS_M_BACK_3)){
                for (Mob m : Gamestate.e.mobs){
                    if (m.pos==pos && enemy_target_ok(m))
                        targets.add(m);
                }
            }
            return targets;
        } else {
            return new ArrayList<Mob>();
        }
    }

    void trigger(){
        c.current_stance = null;
        last_used = Gamestate.w.clock;
        if (get_delay()>0){
            c.action_in_progress = this;
            c.action_fires = Gamestate.w.clock + get_delay();
        } else {
            resolve();
        }
    }

    void resolve(){
        c.current_stance = null;
        if ((target_friend() && !friend_target_ok(char_target)) || (target_enemy() && !enemy_target_ok(mob_target)) || (c.energy < cost())){
        	Gamestate.add_message("Action failed",c.image,Color.WHITE);
        } else {
            c.energy = c.energy - cost();
            if (limited_uses!=null)
                limited_uses = limited_uses - 1;
            c.flash_image = "verypale";
            if (!message().equals(""))
            	Gamestate.add_message(message(),c.image,Color.WHITE);
            if (potion_code!=null)
            	c.potions_used.add(potion_code);
            make_stuff_happen();
        }
    }

    void make_stuff_happen(){
        // stub;
    }

    String out_of_game_description(){
    	return ""; // stub
    }

    String get_description(){
    	String result = describe_resolution();
        if (get_delay() > 0)
            result = result + "\r\n" + Math.round((get_delay()/Constants.TIME_SCALAR)*10.0)/10.0 + " s delay";
        if (get_cooldown()!=null)
            result = result + "\r\n" + Math.round((get_cooldown()/Constants.TIME_SCALAR)*10.0)/10.0 + " s cooldown";
        if (disruptable())
            result = result + "\r\n" + "Disrupted if you take damage";
        if (limited_uses!=null)
            result = result + "\r\n" + limited_uses + " uses remaining";
        if (cost()>0)
            result = result + "\r\n" + "Costs " + cost() + " bar";
        if (describe_reflex_condition()!=null)
            result = result + "\r\n" + "Can be used by reflex if " + describe_reflex_condition() + " (" + (int)(reflex_chance(c.get_reflexes(),c.level,reflex_level())) + "% chance)";
        return result;
    }

    String describe_resolution(){
        return null; // stub;
    }

    String describe_reflex_condition(){
        return null; // stub;
    }

    double increase(){
		// only used in a couple of cases
		return 0;
	}

	Integer success_chance(){
		// only used in a couple of cases
		return 0;
	}

	double chance(){
		// only used in a couple of cases
		return 0;
	}

    static double cost_mult(int stamina){
        if (stamina<=1)
        	return 2;
    	else if (stamina==2)
        	return 1.6;
    	else if (stamina==3)
        	return 1.2;
    	else if (stamina==4)
        	return 1;
    	else if (stamina==5)
        	return 0.85;
    	else if (stamina==6)
        	return 0.7;
    	else if (stamina==7)
        	return 0.65;
        return 0.6;
    }

    static int success_chance(int x){
        if (x>=12)
            return 100;
        if (x==11)
            return 99;
        if (x==10)
            return 97;
        if (x==9)
            return 95;
        if (x==8)
            return 90;
        if (x==7)
            return 70;
        if (x==6)
            return 50;
        if (x==5)
            return 30;
        if (x==4)
            return 10;
        if (x==3)
            return 5;
        if (x==2)
            return 3;
        if (x==1)
            return 1;
        return 0;
    }

    static int reflex_chance(int reflexes,int level,int action_reflex_level){
        int result = 20 + (level + (reflexes-3) - action_reflex_level) * 15;
        return Math.max(5,Math.min(result,success_chance(reflexes + 3)));
    }

    static double round_to_1_dp(double x){
        return Math.round(x*10.0)/10.0;
    }

    int requires_strength(){
    	return 0;}

    int requires_skill(){
    	return 0;}

    int requires_valor(){
    	return 0;}

    int requires_wisdom(){
    	return 0;}

    int requires_daring(){
    	return 0;}

    int requires_cunning(){
    	return 0;}

    int requires_power(){
    	return 0;}

    int requires_subtlety(){
    	return 0;}

    int requires_reflexes(){
    	return 0;}

    int requires_constitution(){
    	return 0;}

    int requires_stamina(){
    	return 0;}

    int requires_training(){
    	return 0;}

    int requires_level(){
    	return 1;}

    boolean priest_ok(){
    	return false;}

    boolean warrior_ok(){
    	return false;}

    boolean mage_ok(){
    	return false;}

    boolean rogue_ok(){
    	return false;}

    ArrayList<Character_action_code> prerequisites(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> obsoletes(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> prevents(){
    	return new ArrayList<Character_action_code>();}

    Integer gold_cost(){
    	return 0;}

    Action_color_code color(){
    	return Action_color_code.ACC_WHITE;}

    boolean never_learnable(){
    	return false;
    }
    
    boolean recommended(){
    	return false;}
}


class Spell_CA extends Character_action {
    public Spell_CA(){
    	super();
    }

    double delay(){
        return 2.0;
    }

    String message(){
        return "'Shazam!'";
    }

    boolean disruptable(){
        return true;
    }
}

class Self_sacrifice_CA extends Spell_CA {
    public Self_sacrifice_CA(){
    	super();
    }

    String name(){
        return "Self Sacrifice";
    }

    void make_stuff_happen(){
    	c.die();
        Gamestate.add_sound("sacrifice");
        for (Character c2 : Gamestate.p.chars){
        	if (c2.alive && !c2.about_to_die){
        		int old_health = c2.health;
        		c2.health = (int)Math.min(c2.max_health, c2.health + 7);
        		c2.energy = (int)Math.min(c2.max_energy, c2.energy + 7);
            	c2.flash_number = c2.health - old_health;
            	c2.number_starts = Gamestate.w.clock;
            	c2.number_color = Color.GREEN;
        	}
        }
    }

    int requires_level(){
    	return 6;}

    boolean priest_ok(){
    	return true;}

    String out_of_game_description(){
    	return "Sacrifice yourself, but give health and energy to your friends.";
    }

    String describe_resolution(){
        return "Sacrifice yourself, but each other surviving character gains 7 health and 7 energy";
    }

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}
}

class Spotter_CA extends Character_action {
    public Spotter_CA(){
    	super();
    }

    String name(){
        return "Spotter";
    }

    boolean front_row_ok(){
        return false;
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("good_spell");
        if (mob_target.alive && !mob_target.about_to_die){
          	mob_target.spotted_until = Gamestate.w.clock + 10;
        }
    }

    String out_of_game_description(){
    	return "A back-row rogue can use this ability to help his friends to hit evasive monsters.";
    }

    String describe_resolution(){
        return "The target loses half its evasion rating for a few seconds";
    }

    int requires_cunning(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class Slow_CA extends Spell_CA {
    public Slow_CA(){
    	super();
    }

    String name(){
        return "Slow Monster";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_ok(Mob m){
    	return super.enemy_target_ok(m) && m.level<=7;
    }

    Double cooldown(){
    	return 10.0;
    }

    int base_cost(){
        return 10;
    }

    double duration(){
    	return (c.subtlety-2)*2.0;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("good_spell");
        if (mob_target.alive && !mob_target.about_to_die){
          	mob_target.slow_until = Gamestate.w.clock + duration();
        }
    }

    String out_of_game_description(){
    	return "This spell magically slows down a monster for a few seconds, so that it attacks and uses its abilities less often. Some high level monsters are immune. Works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "The target uses its attacks and abilities less often for "+(round_to_1_dp(duration()/Constants.TIME_SCALAR))+" seconds. Some high level monsters are immune";
    }

    int requires_subtlety(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}

class Mockery_CA extends Character_action {
    public Mockery_CA(){
    	super();
    }

    String name(){
        return "Mockery";
    }

    ArrayList<String> messages(){
        ArrayList<String> m = new ArrayList<String>();
        m.add("Take that, you gibbering ghoul!");
        m.add("Why don't you crawl back to the hole you came from!");
        m.add("Run home to your mama!");
        m.add("My mother-in-law is scarier than you!");
        m.add("These monsters are rubbish, I want my money back!");
        m.add("Pithecanthropus! Iconoclast! Ectoplasm!");
        m.add("Ha! I bet that hurt!");
        m.add("BURN!!!!");
        m.add("Bastard son of a thousand louse-ridden sludge beasts!");
        m.add("All your bases are belong to us!");
        m.add("L2P n00b!!!!1!1!1");
        m.add("Prithee, I am the king of the castle, and thou art the dirty rascal");
    	return m;
    }

    void make_stuff_happen(){
        int energy_gain = Gamestate.w.mobs_damage_in_last_few_seconds(4.0) / 50;
        if (energy_gain<=0){
            Gamestate.add_sound("cancel");
            Gamestate.add_message("Your mockery falls flat.",c.image,Color.WHITE);
            return;
        }
        Gamestate.add_message(messages().get(Gamestate.w.randint(0,messages().size()-1)),c.image,Color.WHITE);
        for (Character cc : Gamestate.p.chars){
        	if (cc.alive && !cc.about_to_die){
        		Gamestate.add_sound("mockery");
        		cc.energy = (int)Math.min(cc.energy + energy_gain, cc.max_energy);
        	}
        }
    }

    double delay(){
    	return 1.0;
    }

    Double cooldown(){
    	return 5.0;
    }

    boolean needed(){
    	return Gamestate.w.mobs_damage_in_last_few_seconds(3.0)>50;
    }

    int reflex_level(){
        return 7;
    }

    String describe_reflex_condition(){
        return "you inflict enough damage on your enemies";
    }

    String out_of_game_description(){
    	return "Your rogue can mock your enemies immediately after you inflict a lot of damage on them. All your characters recover a small amount of blue bar.";
    }

    String describe_resolution(){
        return "All characters gain one point of blue bar for each 50 points of damage your party has inflicted in the last few seconds (rounded down)";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_daring(){
    	return 5;}

    int requires_level(){
    	return 6;
    }

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}
}

class Undaunted_CA extends Character_action {
    public Undaunted_CA(){
    	super();
    }

    String name(){
        return "Undaunted";
    }

    double delay(){
    	return 1.0;
    }

    Double cooldown(){
    	return 5.0;
    }

    void make_stuff_happen(){
        int energy_gain = 10;
        Gamestate.add_sound("good_spell");
        c.energy = (int)Math.min(c.energy + energy_gain, c.max_energy);
    }

    boolean ok(){
    	return super.ok() && needed();
    }

    boolean needed(){
    	return Gamestate.w.party_damage_in_last_few_seconds(3.0)>50;
    }

    int reflex_level(){
        return 3;
    }

    String describe_reflex_condition(){
        return "the party is heavily damaged";
    }

    String out_of_game_description(){
    	return "When your party takes heavy damage, your character can rally themselves and regain blue bar.";
    }

    String describe_resolution(){
        return "Regain ten blue bar. Only usable when your party has taken at least fifty points of damage in the last few seconds";
    }

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 6;
    }

    int requires_valor(){
    	return 3;}
    int requires_constitution(){
    	return 5;}
    int requires_strength(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}
}

class Super_smite_CA extends Smite_CA {
    public Super_smite_CA(){
    	super();
    }

    String name(){
        return "Super Smite";
    }

    String message(){
    	return "RAR!";
    }

    int base_cost(){
        return 20;
    }

    double damage_mult(){
        return 2.5;
    }

    double delay(){
    	return 1.2;
    }

    Double cooldown(){
        return 12.0;
    }

    int requires_level(){
    	return 7;}

    int requires_strength(){
    	return 6;}

    boolean priest_ok(){
    	return false;}

    boolean needed(){
    	return false;
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SMITE);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}

    String out_of_game_description(){
    	return "A super powerful melee attack.";
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for +150% damage. Can even break through Block sometimes";
    }
}

class Theurgic_wave_CA extends Spell_CA {
    public Theurgic_wave_CA(){
    	super();
    }

    String name(){
        return "Theurgic Wave";
    }

    int base_cost(){
        return 25;
    }

    double delay(){
    	return 0.5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("lightning_bolt");
        for (Character c2 : Gamestate.p.chars){
        	if (c2.alive && !c2.about_to_die && c2.action_in_progress!=null && c2.action_in_progress.disruptable())
        		c2.action_in_progress = null;
        }
        for (Mob m : Gamestate.e.mobs){
        	if (m.alive && m.about_to_die && m.action_in_progress!=null && m.action_in_progress.disruptable())
        		m.action_in_progress = null;
        }
    }

    String out_of_game_description(){
    	return "This powerful counterspell can disrupt almost any other spell that is not yet completed. It is expensive, however...";
    }

    String describe_resolution(){
        return "Disrupt all spells that are currently being cast";
    }

    int requires_level(){
    	return 7;}

    int requires_stamina(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class Summon_friend_CA extends Spell_CA {
    public Summon_friend_CA(){
    	super();
    	limited_uses = 1;
    }

    String name(){
        return "Summon Friend";
    }

    int base_cost(){
        return 15;
    }

    Double cooldown(){
        return 15.0;
    }

    double delay(){
    	return 3.5;
    }

    String out_of_game_description(){
    	return "This ability allows you to bring one of your absent friends instantly to your side. There must be a gap in your party to summon into.";
    }

    String describe_resolution(){
        return "Summon another guild member to fill a gap in your party";
    }

    boolean ok(){
        return super.ok() && Gamestate.p.n_surviving_chars()<6;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("summon");
        int index = choose_cs();
        if (index<0) return;
        Charsheet cs = Campaignstate.chars.get(index);
        Campaignstate.current_party.add(index);
 		Position_code pos = Gamestate.p.last_free_back_pos();
 		if (pos==null) pos = Gamestate.p.last_free_front_pos();
 		if (pos==null) return;
		Character cc = Gamestate.p.new Character(cs,Gamestate.p.chars.size(),pos);
 		cc.slide_from = Position_code.POS_DOWN;
 		cc.slide_to = cc.pos;
 		cc.slide_start = Gamestate.w.clock;
 		cc.slide_finish = Gamestate.w.clock + 0.3;
	 	Gamestate.p.chars.add(cc);
    }

    int requires_subtlety(){
    	return 6;}
    int requires_level(){
    	return 6;}

    boolean mage_ok(){
    	return true;
    }

    int choose_cs(){
    	ArrayList<Integer> options = new ArrayList<Integer>();
    	ArrayList<Integer> levels = new ArrayList<Integer>();
    	int max_level = 1;
    	for (int i=0; i<Campaignstate.chars.size(); i++){
    		Charsheet cs = Campaignstate.chars.get(i);
    		boolean available = true;
    		for (Character c : Gamestate.p.chars){
    			if (c.image.equals(cs.image)){
    				available = false;}
    		}
    		if (available){
    			options.add(i);
    			levels.add(cs.level);
    			max_level = Math.max(max_level, cs.level);
    		}
    	}
    	int index;
    	if (options.size()>0){
    		for (int i=0; i<20; i++){
    			index = Gamestate.w.randint(0, options.size()-1);
    			if (Gamestate.w.rand.nextDouble() < Math.pow(0.5,max_level - levels.get(index))){
    				return options.get(index);
    			}
    		}
    	}
    	return -1;
    }
}

class Life_leech_CA extends Spell_CA {
    public Life_leech_CA(){
    	super();
    }

    String name(){
        return "Life Leeching";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_LIFE_LEECH,new Effect_parameters(20));
    }

    String out_of_game_description(){
    	return "When used, this ability enables you to regain health whenever you damage an enemy with your basic melee attack. The more damage you do, the more health you recover.";
    }

    String describe_resolution(){
        return "Grant life leeching for " + (round_to_1_dp(20/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SHOCKWAVE);
    	return a;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}


class Fear_CA extends Spell_CA {
    public Fear_CA(){
    	super();
    }

    String name(){
        return "Fear";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Behold - a horrible illusion!";
    }

    int base_cost(){
        return 8;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_ok(Mob m){
        if (super.enemy_target_ok(m))
        	if (m.alive && !m.about_to_die && !m.undead && !m.construct && !m.never_encountered_randomly && !m.dragon && !m.confusion_resistant)
                return true;
        return false;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (enemy_target_ok(m))
                    return true;
        return false;
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target) && Gamestate.w.randint(1,100)<=success_chance(9 + c.subtlety_for_fear + c.level - 2*mob_target.level)){
        	mob_target.flee();
        } else {
            Gamestate.add_sound("cancel");
            Gamestate.add_message("Unaffected",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This spell creates a terrifying illusion that makes one of your enemies run away. Some monsters, however, are immune to fear.";
    }

    String describe_resolution(){
        return "Scare one monster into running away. It is not slain and does not yield experience or treasure, but will trouble you no more";
    }

    int requires_subtlety(){
    	return 4;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Physical_resistance_CA extends Character_action {
    public Physical_resistance_CA(){
    	super();
    }

    String name(){
        return "Excellent Defense";
    }

    boolean callable(){
        return false;
    }

    String describe_resolution(){
        return "The Shield of Locris reduces the damage done by enemies' normal melee attacks by 25%, before your armor is taken into account";
    }
}

class Stun_resistance_CA extends Character_action {
    public Stun_resistance_CA(){
    	super();
    }

    String name(){
        return "Stun Resistance";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Protects the character from being stunned by enemies.";
    }

    String describe_resolution(){
        return "Makes this character immune to stunning.";
    }

    int requires_constitution(){
    	return 4;}

    int requires_level(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}
}

class Detect_magic_CA extends Character_action {
    public Detect_magic_CA(){
    	super();
    }

    String name(){
        return "Detect Magic";
    }

    boolean callable(){
        return false;
    }

    double increase(){
        return (9 + c.subtlety) / 10.0;
    }

    String out_of_game_description(){
    	return "This ability makes the party more likely to find magic items in random dungeons. It works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Likely to find " + (int)(Math.round(100*(increase()-1))) + "% more items in random dungeons";
    }

    int requires_subtlety(){
    	return 2;}

    boolean mage_ok(){
    	return true;}
}

class Shorten_the_tale_CA extends Spell_CA {
    public Shorten_the_tale_CA(){
    	super();
    }

    String name(){
        return "Shorten the Tale";
    }

    int base_cost(){
        return 2;
    }

    void make_stuff_happen(){
        Gamestate.w.fast_time = true;
    }

    String out_of_game_description(){
    	return "This spell speeds up time, allowing you to quickly 'fast forward' through an easy fight.";
    }

    String describe_resolution(){
        return "Speeds up the passage of time greatly until the screen is next clear of enemies";
    }

    boolean ok(){
    	return super.ok() && Gamestate.e.n_surviving_mobs()>0;
    }

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Rebuke_CA extends Character_action {
    public Rebuke_CA(){
    	super();
    }

    String name(){
        return "Rebuke";
    }

    Double cooldown(){
        return 10.0;
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 5;
    }

    double delay(){
        return 0.4;
    }

    int damage(){
    	return 15;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("smite");
        Gamestate.add_message("Let that serve you right!",c.image,Color.WHITE);
        mob_target.take_damage(Gamestate.w.randint(damage()/2,(3*damage())/2));
    }

    String out_of_game_description(){
    	return "Damage an enemy whose spell has just been countered.";
    }

    String describe_resolution(){
        return "Cast this quickly after using a counterspell, to do an average of " + damage() + " damage to the monster whose spell or gaze was countered.";
    }

    boolean enemy_target_ok(Mob m){
    	if (!super.enemy_target_ok(m))
    		return false;
    	return m.alive && !m.about_to_die && m.countered_at >= Gamestate.w.clock - 3.0;
    }

    boolean ok(){
        if (!super.ok()) return false;
        for (Mob m : Gamestate.e.mobs)
            if (enemy_target_ok(m))
                return true;
        return false;
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean needed(){
        return ok();
    }

    void set_reflex_target(){
        for (Mob m : Gamestate.e.mobs){
            if (enemy_target_ok(m)){
            	mob_target=m;
            	return;
            }
		}
    }

    String describe_reflex_condition(){
        return "an enemy spell is successfully countered";
    }

    int reflex_level(){
        return 7;
    }
}

class Finishing_blow_CA extends Character_action {
    public Finishing_blow_CA(){
    	super();
    }

    String name(){
        return "Finishing Blow";
    }

    Double cooldown(){
        return 3.0;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 6;
    }

    double damage_mult(){
        return 2.0;
    }

    double delay(){
        return 0.4;
    }

    void make_stuff_happen(){
        if (mob_target.stunned && c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("kill");
            Gamestate.add_message("'Die!!'",c.image,Color.WHITE);
            int armor = mob_target.current_armor();
            if (c.has_status_effect(Status_effect_code.EF_FIND_WEAKNESS))
                armor = Math.max(0,armor-5);
            mob_target.take_damage(Math.max(0,(int)Math.round(2 * c.melee_damage_roll(mob_target)))-armor);
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This ability can be used to heavily damage a stunned opponent.";
    }

    String describe_resolution(){
        return "Attack a stunned enemy, in the front row, for double damage.";
    }

    boolean enemy_target_ok(Mob m){
    	if (!super.enemy_target_ok(m))
    		return false;
    	return m.alive && !m.about_to_die && m.front_row() && m.stunned;
    }

    boolean ok(){
        if (!super.ok()) return false;
        for (Mob m : Gamestate.e.mobs)
            if (enemy_target_ok(m))
                return true;
        return false;
    }

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_daring(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean needed(){
        if (!super.ok()) return false;
        for (Mob m : Gamestate.e.mobs)
            if (enemy_target_ok(m) && m.health>0 && (m.health>=10 || m.max_health>=100))
                return true;
        return false;
    }

    void set_reflex_target(){
        for (Mob m : Gamestate.e.mobs){
            if (enemy_target_ok(m)){
            	mob_target = m;
            	return;
            }
		}
    }

    String describe_reflex_condition(){
        return "a front-row opponent is stunned";
    }

    int reflex_level(){
        return 7;
    }
}

class Shoot_NeverUsed_CA extends Character_action {
    public Shoot_NeverUsed_CA(){
    	super();
    }

    String name(){
        return "Shoot";
    }

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    int requires_skill(){
    	return 3;}

    String out_of_game_description(){
    	return "This ability allows the warrior to use a missile weapon such as a bow or crossbow. Most warriors have no missile attack.";
    }
}

class Haggler_CA extends Character_action {
    public Haggler_CA(){
    	super();
    }

    String name(){
        return "Haggler";
    }

    boolean rogue_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}

    int requires_cunning(){
    	return 4;}
    int requires_subtlety(){
    	return 4;}

    String out_of_game_description(){
    	return "This ability allows you to bargain for better prices at the Alchemist's shop.";
    }
}

class Inspiring_CA extends Character_action {
    public Inspiring_CA(){
    	super();
    }

    String name(){
        return "Inspiring";
    }

    boolean warrior_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    int requires_skill(){
    	return 5;}
    int requires_valor(){
    	return 5;}
    int requires_level(){
    	return 5;}

    String out_of_game_description(){
    	return "If any character in your guild has this ability, you pay 20% less to recruit new characters at the Inn.";
    }
}

class Carouse_CA extends Character_action {
    public Carouse_CA(){
    	super();
    }

    String name(){
        return "Carouse";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_cunning(){
    	return 6;}

    String out_of_game_description(){
    	return "If any character in your guild has this ability, you pay 20% less to recruit new characters at the Inn.";
    }
}

class Sling_NeverUsed_CA extends Character_action {
    public Sling_NeverUsed_CA(){
    	super();
    }

    String name(){
        return "Shoot";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    int requires_valor(){
    	return 2;}

    String out_of_game_description(){
    	return "This ability allows the priest to use a sling at long range. Most priests have no missile attack.";
    }
}

class Zen_archer_CA extends Character_action {
    public Zen_archer_CA(){
    	super();
    }

    String name(){
        return "Zen Archer";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    int requires_valor(){
    	return 3;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SLING);
    	return a;}

    String out_of_game_description(){
    	return "This ability allows the priest to use a bow at long range. Most priests have no missile attack.";
    }
}

class Bash_CA extends Character_action {
    public Bash_CA(){
    	super();
    }

    String name(){
        return "Bash";
    }

    Double cooldown(){
        return 6.0;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 6;
    }

    double damage_mult(){
        return 1.3;
    }

    double delay(){
        return 0.4;
    }

    void make_stuff_happen(){
        if (c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("smite");
            //Gamestate.add_message("THUMP!",c.image,Color.WHITE);
            int armor = mob_target.current_armor();
            if (c.has_status_effect(Status_effect_code.EF_FIND_WEAKNESS))
                armor = Math.max(0,armor-5);
            mob_target.take_damage(Math.max(0,(int)Math.round(damage_mult() * c.melee_damage_roll(mob_target)))-armor);
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for +30% damage";
    }

    String out_of_game_description(){
    	return "A powerful melee attack.";
    }

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((2 * c.max_energy) / 3))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && m.front_row()){
                    if (m.health >= 30){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row()){
                if (m.health >= 30){
                	mob_target = m;
                    return;
                }
            }
        }
    }

    String describe_reflex_condition(){
        if (char_is_aggressive()){
            return "you have plenty of energy and there is an opponent with at least 30 health before you";
        } else {
            return null;
        }
    }

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean recommended(){
    	return true;}    
}

class Flurry_CA extends Bash_CA {
    public Flurry_CA(){
    	super();
    }

    String name(){
        return "Flurry";
    }

    Double cooldown(){
        return 1.0;
    }

    int base_cost(){
        return 4;
    }

    double damage_mult(){
        return 0.7;
    }

    double delay(){
        return 0.2;
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for two-thirds normal damage";
    }

    String out_of_game_description(){
    	return "A quick melee attack against a target of your choice.";
    }

    boolean rogue_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean warrior_ok(){
    	return false;}

    int requires_daring(){
    	return 4;}
    int requires_subtlety(){
    	return 2;}
    int requires_power(){
    	return 2;}

    boolean recommended(){
    	return false;}
}

class Polearm_strike_CA extends Smite_CA{
    public Polearm_strike_CA(){
    	super();
    }

    boolean never_learnable(){
    	return true;}

    String name(){
        return "Polearm Strike";
    }

    boolean front_row_ok(){
        return false;
    }

    boolean back_row_ok(){
        return true;
    }

    boolean priest_ok(){
    	return false;}

    String describe_resolution(){
        return super.describe_resolution() + ". Used from the back row";
    }

    String out_of_game_description(){
    	return "A powerful melee attack, used from the back row.";
    }
}

class Smite_CA extends Bash_CA {
    public Smite_CA(){
    	super();
    }

    String name(){
        return "Smite";
    }

    int base_cost(){
        return 10;
    }

    double damage_mult(){
        return 1.8;
    }

    String out_of_game_description(){
    	return "An extra powerful melee attack.";
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for +80% damage";
    }

    int requires_valor(){
    	return 3;}

    int requires_strength(){
    	return 2;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BASH);
    	a.add(Character_action_code.CA_HEALING);
    	a.add(Character_action_code.CA_SACRIFICE);
    	a.add(Character_action_code.CA_FRONT_ROW_BUFF);
    	a.add(Character_action_code.CA_UNDEAD_SLAYER);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BASH);
    	return a;}
}

class Deathblow_CA extends Character_action {
    public Deathblow_CA(){
    	super();
    }

    String name(){
        return "Deathblow";
    }

    double delay(){
    	return 0.4;
    }

    Double cooldown(){
        return 3.0;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 8;
    }

    double damage_mult(){
        return 1.3;
    }

    void make_stuff_happen(){
        if (c.melee_hit_roll(mob_target)){
            int armor = mob_target.current_armor();
            if (c.has_status_effect(Status_effect_code.EF_FIND_WEAKNESS))
                armor = Math.max(0,armor-5);
            if ((mob_target.health <= 0.3 * mob_target.max_health) && (mob_target.health <= 30) && ((int)Math.round(damage_mult() * c.melee_damage_roll(mob_target)) > armor)){
                Gamestate.add_sound("kill");
                Gamestate.add_message("'Die!!'",c.image,Color.WHITE);
                mob_target.take_damage(999);
            } else {
                Gamestate.add_sound(c.melee_miss_sound);
                Gamestate.add_message("Failed!",c.image,Color.WHITE);
            }
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This ability can be used to finish off a weakened opponent.";
    }

    String describe_resolution(){
        return "Attack a front row target of your choice. If you hit and penetrate its armor, and the target is on less than 30% max health and has less than 30 health, it dies immediately";
    }

    int reflex_level(){
        return 6;
    }

    boolean enemy_target_ok(Mob m){
    	if (!super.enemy_target_ok(m))
    		return false;
    	if (m.undead || m.construct)
    		return false;
    	return m.alive && !m.about_to_die && m.front_row() && (m.health <= 0.3 * m.max_health) && (m.health <= 40) && (m.max_health >= 70);
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (enemy_target_ok(m))
                return true;
        return false;
    }

    boolean ok(){
        return super.ok() && needed();
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
        	if (enemy_target_ok(m)){
        		mob_target = m;
                return;
            }
        }
    }

    String describe_reflex_condition(){
        return "a strong enemy is near death";
    }

    boolean warrior_ok(){
    	return true;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_daring(){
    	return 4;}

    int requires_skill(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Swipe_CA extends Character_action {
    public Swipe_CA(){
    	super();
    }

    String name(){
        return "Swipe";
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 10;
    }

    Double cooldown(){
        return 4.0;
    }

    boolean berserkable(){
    	return true;
    }

    int accuracy(){
        return -3;
    }

    double delay(){
        return 0.4;
    }

    boolean ok(){
        if (Gamestate.e.n_surviving_front_mobs()==0)
            return false;
        return super.ok();
    }

    void make_stuff_happen(){
        int hits = 0;
        c.accuracy = c.accuracy + accuracy();
        for (Mob target : Arrays.asList(Gamestate.e.get_monster_at_pos(Position_code.POS_M_FRONT_1),Gamestate.e.get_monster_at_pos(Position_code.POS_M_FRONT_2),Gamestate.e.get_monster_at_pos(Position_code.POS_M_FRONT_3))){
            if (target!=null){
                if (c.melee_hit_roll(target)){
                    target.take_damage(Math.max(0,c.melee_damage_roll(target)-target.current_armor()));
                    hits = hits + 1;
                }
            }
        }
        c.accuracy = c.accuracy - accuracy();
        if (hits>0){
            Gamestate.add_sound("cleave");
            //Gamestate.add_message("SWOOSH!",c.image,Color.WHITE);
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "A rather inaccurate attack against the entire enemy front row.";
    }

    String describe_resolution(){
        return "Attack all front row targets at once, at -3 accuracy";
    }

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((2 * c.max_energy) / 3))
                return false;
            int count = 0;
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && (!m.about_to_die) && m.front_row())
                    count = count + 1;
            if (count==3)
                return true;
        }
        return false;
    }

    String describe_reflex_condition(){
        if (char_is_aggressive()){
            return "you have plenty of energy and there are three front-row opponents before you";
        } else {
            return null;
        }
    }

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean recommended(){
    	return true;}
}

class Cleave_CA extends Swipe_CA {
    public Cleave_CA(){
    	super();
    }

    String name(){
        return "Cleave";
    }

    int base_cost(){
        return 15;
    }

    int accuracy(){
        return 0;
    }

    String out_of_game_description(){
    	return "An accurate attack against the entire enemy front row. Replaces Swipe.";
    }

    String describe_resolution(){
        return "Attack all front row targets at once, with no loss of accuracy";
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SWIPE);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SWIPE);
    	return a;}
}

class Throw_CA extends Character_action {
    public Throw_CA(){
    	super();
    }

    String name(){
        return "Hurled Axe";
    }

    double delay(){
        return 1.0;
    }

    boolean front_row_ok(){
        return false;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        int needed = 2 * (5 + c.skill/2 - mob_target.current_evasion());
        if (Gamestate.w.randint(1,20)<=needed){
            //Gamestate.add_message("Whizz... THUNK!",c.image,Color.WHITE);
            Gamestate.add_sound("hit");
        	mob_target.take_damage(Math.max(0,Gamestate.w.randint(2,16)-mob_target.current_armor()));
        } else {
            Gamestate.add_sound("miss");
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "A missile attack against a specific enemy. Can be useful for disrupting enemy spellcasters. Works better if you have high Skill.";
    }

    String describe_resolution(){
        return "A missile attack doing 2-16 damage to a front row target, if it hits";
    }

    int requires_skill(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Arrow_cutting_CA extends Deflect_CA {
    public Arrow_cutting_CA(){
    	super();
    }

    String name(){
        return "Arrow Cutting";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_DEFLECT;
        c.stance_wears_off = Gamestate.w.clock + 2.5;
    }

    int requires_level(){
    	return 5;}

    int requires_daring(){
    	return 6;}

    boolean rogue_ok(){
    	return true;}

    boolean warrior_ok(){
    	return false;}
}

class Deflect_CA extends Character_action {
    public Deflect_CA(){
    	super();
    }

    String name(){
        return "Deflect";
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_DEFLECT;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    double pause(){
        return 0.5;
    }

    boolean needed(){
    	for (Character c : Gamestate.p.chars)
    		if (c.alive && !c.about_to_die)
    			if (c.current_stance!=null && c.current_stance==Stance_code.ST_DEFLECT)
    				return false;
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.deflectable())
                if (m.action_fires <= Gamestate.w.clock + pause())
                    return true;
        return false;
    }

    int reflex_level(){
        return 3;
    }

    String out_of_game_description(){
    	return "A defense against enemies that can snipe your characters (like troglodyte archers).";
    }

    String describe_resolution(){
        return "Block a special missile attack";
    }

    String describe_reflex_condition(){
        return "required";
    }

    int requires_skill(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class Invulnerability_CA extends Character_action {
    public Invulnerability_CA(){
    	super();
    }

    String name(){
        return "Forcefield";
    }

    Double cooldown(){
        return 6.0;
    }

    boolean disruptable(){
        return true;
    }

    double delay(){
        return 1.0;
    }

    String message(){
        return "'Shazam!'";
    }

    int base_cost(){
        return 10;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("invulnerable");
    	for (Character c : Gamestate.p.chars){
    		if (c.alive && !c.about_to_die){
    	        Gamestate.add_sound("invulnerable");
    			c.current_stance = Stance_code.ST_INVULNERABLE;
    			c.stance_wears_off = Gamestate.w.clock + duration();
    		}
    	}
    }

    double duration(){
        return Math.max(0.4, 0.3*(c.power-1));
    }

    String out_of_game_description(){
    	return "A spell that protects the entire party from all damage for a brief period. Works better if you have high Power.";
    }

    String describe_resolution(){
        return "Makes the entire party immune from physical damage for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class DeflectMissile_CA extends Deflect_CA {
    public DeflectMissile_CA(){
    	super();
    }

    String name(){
        return "Avert Missile";
    }

    double pause(){
        return 1;
    }

    int base_cost(){
        return 5;
    }

    boolean back_row_ok(){
        return true;
    }

    boolean front_row_ok(){
        return false;
    }

    int reflex_level(){
        return 5;
    }

    int requires_subtlety(){
    	return 3;}

    boolean warrior_ok(){
    	return false;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class Catch_boulder_CA extends Character_action {
    public Catch_boulder_CA(){
    	super();
    }

    String name(){
        return "Catch Boulder";
    }

    int base_cost(){
        return 6;
    }

    Double cooldown(){
    	return 4.0;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_CATCH;
        c.stance_wears_off = Gamestate.w.clock + 5;
    }

    String out_of_game_description(){
    	return "The character is so strong that they can catch massive missiles.";
    }

    String describe_resolution(){
        return "Defend against a hurled, dropped or rolling boulder. Ineffective against meteors. To catch a falling rock, you must be standing on the flashing red square";
    }

    int requires_strength(){
    	return 6;}

    int requires_level(){
    	return 6;}

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class Block_CA extends Character_action {
    public Block_CA(){
    	super();
    }

    String name(){
        return "Block";
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 3;
    }

    Double cooldown(){
    	return 2.0;
    }
    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_BLOCK;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
    	for (Character c : Gamestate.p.chars)
    		if (c.alive && !c.about_to_die)
    			if (c.current_stance!=null && c.current_stance==Stance_code.ST_BLOCK)
    				return false;
        if (c.current_stance==Stance_code.ST_EPIC_BLOCK)
            return false;
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && (m.action_in_progress.blockable() || m.action_in_progress.semi_blockable()))
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "A defense against enemies that can smite your characters (like orc warriors).";
    }

    String describe_resolution(){
        return "Block a Smite attack";
    }

    String describe_reflex_condition(){
        return "required";
    }

    int requires_skill(){
    	return 3;}

    int requires_valor(){
    	return 3;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}

    boolean recommended(){
    	return true;}
}

class Epic_Block_CA extends Block_CA {
    public Epic_Block_CA(){
    	super();
    }

    String name(){
        return "Epic Block";
    }

    int base_cost(){
        return 8;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_EPIC_BLOCK;
        c.stance_wears_off = Gamestate.w.clock + duration();
    }

    double duration(){
        return 4.0;
    }

    int reflex_level(){
        return 7;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.epic_blockable())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "A defense against enemies that can super-smite your characters (like giants).";
    }

    String describe_resolution(){
        return "Lasts for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds. During this time you block all Smite attacks. Super Smite is mostly blocked but will still cause 20% normal damage.";
    }

    int requires_skill(){
    	return 4;}

    boolean warrior_ok(){
    	return true;}

    boolean priest_ok(){
    	return false;}

    int requires_level(){
    	return 7;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BLOCK);
    	return a;}
}

class Leap_Aside_CA extends Block_CA {
    public Leap_Aside_CA(){
    	super();
    }

    String name(){
        return "Leap Aside";
    }

    int base_cost(){
        return 6;
    }

    boolean back_row_ok(){
        return true;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_LEAP_ASIDE;
        c.stance_wears_off = Gamestate.w.clock + 1.2;
    }

    int reflex_level(){
        return 7;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.leap_awayable())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "A defense against enemies that can smite, super-smite or throw boulders or meteors at your characters.";
    }

    String describe_resolution(){
        return "Evades a Smite, Super Smite, boulder or meteor attack. However, you have to time it just right - and for boulders or meteors, you have to be standing in the red flashing square.";
    }

    int requires_daring(){
    	return 5;}

    boolean rogue_ok(){
    	return true;}

    boolean warrior_ok(){
    	return false;}
    boolean priest_ok(){
    	return false;}

    int requires_level(){
    	return 6;}
}

class Riposte_CA extends Character_action {
    public Riposte_CA(){
    	super();
    }

    String name(){
        return "Riposte";
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 4;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_RIPOSTE;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.blockable())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    int reflex_level(){
        return 2;
    }

    String out_of_game_description(){
    	return "A defense against enemies that can smite your characters (like orc warriors). Not always reliable, but it can let you quickly counter-attack.";
    }

    String describe_resolution(){
        return "Block a Smite attack and counterattack immediately. Not always successful, especially against more powerful opponents, but more likely to work if your Daring is high";
    }

    String describe_reflex_condition(){
        return "required";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_daring(){
    	return 3;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class Retrench_CA extends Character_action {
    public Retrench_CA(){
    	super();
    }

    String name(){
        return "Retrench";
    }

    boolean needed(){
        if (c.auto_retrench && (c.energy < c.max_energy))
            if (Gamestate.e.n_surviving_mobs()==0)
                return true;
        return false;
    }

    int reflex_level(){
        return 3;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_RETRENCH;
        c.stance_wears_off = Gamestate.w.clock + 10;
    }

    String out_of_game_description(){
    	return "Allows your warrior to rest and regain energy.";
    }

    String describe_resolution(){
        return "Triples your bar regeneration rate, but prevents you from autofighting and wears off if you act";
    }

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}

    boolean recommended(){
    	return true;}
}

class Ruthless_CA extends Character_action {
    public Ruthless_CA(){
    	super();
    }

    String name(){
        return "Ruthless";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Makes your character attack weakened enemies, hopefully finishing them off.";
    }

    String describe_resolution(){
        return "Prefer to attack weakened enemies, hopefully finishing them off";
    }

    boolean mage_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Unceasing_fire_CA extends Character_action {
    public Unceasing_fire_CA(){
    	super();
    }

    String name(){
        return "Steady Fire";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Makes your character use the Snipe ability (if they have it) without being told to.";
    }

    String describe_resolution(){
        return "Snipe whenever there is a dangerous target in sight";
    }

    int requires_reflexes(){
    	return 2;}

    boolean rogue_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SNIPE);
    	return a;}

    int requires_level(){
    	return 7;}
}

class Wrathful_CA extends Character_action {
    public Wrathful_CA(){
    	super();
    }

    String name(){
        return "Wrathful";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Makes your character use bolt and cloud spells (if they have them) without being told to.";
    }

    String describe_resolution(){
        return "Use bolt and cloud spells by reflex if you have them";
    }

    int requires_reflexes(){
    	return 2;}

    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FIREBOLT);
    	a.add(Character_action_code.CA_LIGHTNING_BOLT);
    	a.add(Character_action_code.CA_POISON_CLOUD);
    	return a;}

    int requires_level(){
    	return 4;}
}

class Zeal_CA extends Character_action {
    public Zeal_CA(){
    	super();
    }

    String name(){
        return "Zeal";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Makes your character use the Smite ability (if they have it) without being told to.";
    }

    String describe_resolution(){
        return "Use Smite by reflex if you have it";
    }

    int requires_reflexes(){
    	return 2;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class Aggressive_CA extends Character_action {
    public Aggressive_CA(){
    	super();
    }

    String name(){
        return "Aggressive";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Makes your character use the Bash, Smite, Swipe or Cleave abilities (if they have them) without being told to.";
    }

    String describe_resolution(){
        return "Use Bash, Smite, Swipe and Cleave by reflex if you have them";
    }

    int requires_reflexes(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BASH);
    	a.add(Character_action_code.CA_SWIPE);
    	return a;}
}

class Adversity_CA extends Character_action {
    public Adversity_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    String name(){
        return "Strength in Adversity";
    }

    String out_of_game_description(){
    	return "Your melee damage gets stronger as you get more and more wounded.";
    }

    String describe_resolution(){
    	return "At full health you do only 80% normal damage, but at 40% health or below you do 140% normal damage";
    }

    int requires_constitution(){
    	return 4;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}


class FireResistance_CA extends Character_action {
    public FireResistance_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    String name(){
        return "Resist Fire";
    }

    String out_of_game_description(){
    	return "You take half damage from fire attacks. Does not stack with other sources of fire resistance.";
    }

    String describe_resolution(){
        return "Take half damage from fire attacks";
    }

    int requires_constitution(){
    	return 5;}

    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    boolean recommended(){
    	return true;}
}

class Lightning_resistance_CA extends FireResistance_CA {
    public Lightning_resistance_CA(){
    	super();
    }

    String name(){
        return "Resist Lightning";
    }

    String out_of_game_description(){
    	return "You take half damage from lightning attacks.";
    }

    String describe_resolution(){
        return "Take half damage from lightning attacks";
    }
}

class Cold_resistance_CA extends FireResistance_CA {
    public Cold_resistance_CA(){
    	super();
    }

    String name(){
        return "Resist Cold";
    }

    String out_of_game_description(){
    	return "You take half damage from cold attacks. Does not stack with other sources of cold resistance.";
    }

    String describe_resolution(){
        return "Take half damage from cold attacks";
    }

    int requires_constitution(){
    	return 4;}
}

class PoisonResistance_CA extends Character_action {
    public PoisonResistance_CA(){
    	super();
    }

    String name(){
        return "Resist Poison";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "You resist most poison attacks. You may take half damage from some strong poisons. Does not stack with other sources of poison resistance.";
    }

    String describe_resolution(){
        return "Resistant to most poison attacks, though may still take half damage from some strong poisons";
    }

    int requires_constitution(){
    	return 4;}

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    boolean recommended(){
    	return true;}
}

class Leader_CA extends Character_action {
    public Leader_CA(){
    	super();
    }

    String name(){
        return "Leader";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "An attack speed bonus for characters that are standing in the middle of the front row.";
    }

    String describe_resolution(){
        return "Gain +2 speed if you are positioned in the center of the front row";
    }

    boolean rogue_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    int requires_daring(){
    	return 5;}

    int requires_skill(){
    	return 5;}

    int requires_valor(){
    	return 5;}
}

class Fast_cast_CA extends Character_action {
    public Fast_cast_CA(){
    	super();}

    String name(){
        return "Fast Cast";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "All your abilities take effect more quickly.";}

    String describe_resolution(){
        return "Halves the delays on all your spells (and other abilities)";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    int requires_reflexes(){
    	return 6;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FAST_CAST_FRONT_ROW);
    	a.add(Character_action_code.CA_SHAMAN);
    	return a;}
}

class Fast_cast_front_row_CA extends Character_action {
    public Fast_cast_front_row_CA(){
    	super();}

    String name(){
        return "Frontline Caster";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "When you are standing in the front row, all your abilities take effect more quickly.";}

    String describe_resolution(){
        return "Halves the delays on all your spells (and other abilities) when you are in the front row";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SHOCKWAVE);
    	a.add(Character_action_code.CA_SMITE);
    	a.add(Character_action_code.CA_FRONT_ROW_BUFF);
    	a.add(Character_action_code.CA_AGGRO);
    	return a;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FAST_CAST);
    	a.add(Character_action_code.CA_SHAMAN);
    	return a;}
}

class Evasive_CA extends Character_action {
    public Evasive_CA(){
    	super();}

    String name(){
        return "Evasive";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Gives a +2 evasion bonus.";}

    String describe_resolution(){
        return "+2 evasion at all times";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_reflexes(){
    	return 6;}

    int requires_level(){
    	return 4;}
}

class Recuperate_CA extends Character_action {
    public Recuperate_CA(){
    	super();}

    String name(){
        return "Recuperate";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You slowly regain energy over time. This stacks with other sources of energy recovery.";}

    String describe_resolution(){
        return "Regain energy over time";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_stamina(){
    	return 6;}

    int requires_level(){
    	return 4;}
}

class Tough_CA extends Character_action {
    public Tough_CA(){
    	super();}

    String name(){
        return "Tough";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Gives a +2 armor boost.";}

    String describe_resolution(){
        return "+2 armor at all times";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_constitution(){
    	return 6;}

    int requires_level(){
    	return 4;}
}

class Fast_learner_CA extends Character_action {
    public Fast_learner_CA(){
    	super();}

    String name(){
        return "Quick Learner";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You learn quickly, gaining 30% more XP from each adventure.";}

    String describe_resolution(){
        return "Gains XP 30% faster than other characters";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_training(){
    	return 6;}

    int requires_level(){
    	return 1;}
}

class Apothecary_CA extends Character_action {
    public Apothecary_CA(){
    	super();}

    String name(){
        return "Apothecary";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You are familiar with the arts of potions. You can carry four potions instead of the usual three.";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_wisdom(){
    	return 3;}
    int requires_subtlety(){
    	return 3;}
}

class Packrat_CA extends Character_action {
    public Packrat_CA(){
    	super();}

    String name(){
        return "Packrat";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You like to pick up little objects and knick-nacks along the way. You can carry four miscellaneous items instead of the normal three.";}

    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}

class Teacher_CA extends Character_action {
    public Teacher_CA(){
    	super();}

    String name(){
        return "Teacher";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You can train other adventurers. All the other characters accompanying you will gain 10% more XP. This bonus does not stack with other XP increases";}

    String describe_resolution(){
        return "While this character is present, all the other characters in the party gain 10% more XP. Does not stack";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}

    int requires_wisdom(){
    	return 5;}
    int requires_subtlety(){
    	return 5;}

    int requires_level(){
    	return 6;}
}

class Precocious_CA extends Character_action {
    public Precocious_CA(){
    	super();}

    String name(){
        return "Precocious";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Allows you to learn abilities that would normally be one level too high for you";}

    boolean mage_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_training(){
    	return 5;}
}

class Tireless_CA extends Character_action {
    public Tireless_CA(){
    	super();}

    String name(){
        return "Tireless";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Halves the cooldowns on your abilities, allowing you to use them more often.";}

    String describe_resolution(){
        return "Reduces the cooldowns on your abilities by 50%";}

    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_stamina(){
    	return 5;}

    int requires_level(){
    	return 5;}
}

class Hunter_CA extends Character_action {
    public Hunter_CA(){
    	super();}

    String name(){
        return "Hunter";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Gain +2 missile aim at all times.";}

    String describe_resolution(){
        return "+2 missile aim at all times";}

    boolean warrior_ok(){
    	return true;}

    int requires_skill(){
    	return 4;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_LOB);
    	return a;}
}

class Insolent_CA extends Character_action {
    public Insolent_CA(){
    	super();}

    String name(){
        return "Insolent";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "Gain +1 aggro at all times.";
    }

    String describe_resolution(){
        return "+1 aggro at all times";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_daring(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_TAUNT);
    	return a;}
}

class Watchful_CA extends Character_action {
    public Watchful_CA(){
    	super();}

    String name(){
        return "Watchful";}

    boolean callable(){
        return false;}

    String out_of_game_description(){
    	return "You are resistant to sleep spells and gazes.";
    }

    String describe_resolution(){
        return "Resistant to sleep attacks";
    }

	boolean never_learnable(){
		return true;
	}
}

class L8_passive_CA extends Character_action {
    public L8_passive_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    int requires_level(){
    	return 8;}
}

class Captain_CA extends L8_passive_CA {
    public Captain_CA(){
    	super();}

    String name(){
        return "Captain";}

    String out_of_game_description(){
    	return "All party members gain XP at a slightly faster rate.";}

    String describe_resolution(){
        return "All party members gain +10% XP";}

    boolean warrior_ok(){
    	return true;}
}

class Knight_CA extends L8_passive_CA {
    public Knight_CA(){
    	super();}

    String name(){
        return "Knight";}

    String out_of_game_description(){
    	return "It gives a small bonus to your armor and melee accuracy.";}

    String describe_resolution(){
        return "+1 armor, +1 melee accuracy";}

    boolean warrior_ok(){
    	return true;}
}

class Barbarian_CA extends L8_passive_CA {
    public Barbarian_CA(){
    	super();}

    String name(){
        return "Barbarian";}

    String out_of_game_description(){
    	return "It gives a small bonus to your melee attack speed and damage.";}

    String describe_resolution(){
        return "+1 melee attack speed, +10% base melee damage";}

    boolean warrior_ok(){
    	return true;}
}

class Ranger_CA extends L8_passive_CA {
    public Ranger_CA(){
    	super();}

    String name(){
        return "Ranger";}

    String out_of_game_description(){
    	return "It gives a small bonus to your evasion and missile aim.";}

    String describe_resolution(){
        return "+1 missile aim, +1 evasion";}

    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Burglar_CA extends L8_passive_CA {
    public Burglar_CA(){
    	super();}

    String name(){
        return "Burglar";}

    String out_of_game_description(){
    	return "It makes you more effective at Move Silently or Cloak of Shadows.";}

    String describe_resolution(){
        return "The success chance of Move Silently is calculated as if your Cunning was one point higher - or if you have Cloak of Shadows, the success chance is calculated as if your Subtlety was one point higher";}

    boolean rogue_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_STEALTH);
    	return a;}
}

class Thief_CA extends L8_passive_CA {
    public Thief_CA(){
    	super();}

    String name(){
        return "Thief";}

    String out_of_game_description(){
    	return "It makes you more effective at Looter, Lapidary and Pick Locks (if you have those abilities).";}

    String describe_resolution(){
        return "Effect of Looter, Lapidary and Pick Locks is calculated as if your Cunning was one point higher";}

    boolean rogue_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_MORE_GOLD);
    	a.add(Character_action_code.CA_PICK_LOCKS);
    	return a;}
}

class Swashbuckler_CA extends L8_passive_CA {
    public Swashbuckler_CA(){
    	super();}

    String name(){
        return "Swashbuckler";}

    String out_of_game_description(){
    	return "It gives you a small bonus to melee speed and damage.";}

    String describe_resolution(){
        return "+1 melee speed, +10% base melee damage";}

    boolean rogue_ok(){
    	return true;}

    int requires_daring(){
    	return 3;}
}

class Marksman_CA extends L8_passive_CA {
    public Marksman_CA(){
    	super();}

    String name(){
        return "Marksman";}

    String out_of_game_description(){
    	return "It gives you a small bonus to missile accuracy and damage.";}

    String describe_resolution(){
        return "+1 missile accuracy, +10% base missile damage";}

    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_daring(){
    	return 3;}
    int requires_subtlety(){
    	return 3;}
    int requires_power(){
    	return 3;}
}

class Warlock_CA extends L8_passive_CA {
    public Warlock_CA(){
    	super();}

    String name(){
        return "Warlock";}

    String out_of_game_description(){
    	return "It makes you more effective at casting bolt spells.";}

    String describe_resolution(){
        return "Bolt spell damage is calculated as if your Power was one point higher";}

    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FIREBOLT);
    	a.add(Character_action_code.CA_FROST_BOLT);
    	a.add(Character_action_code.CA_LIGHTNING_BOLT);
    	a.add(Character_action_code.CA_POISON_BOLT);
    	return a;}
}

class Thaumaturge_CA extends L8_passive_CA {
    public Thaumaturge_CA(){
    	super();}

    String name(){
        return "Thaumaturge";}

    String out_of_game_description(){
    	return "It makes you more effective at casting mass damage spells.";}

    String describe_resolution(){
        return "Ball, cloud and storm spell damage is calculated as if your Power was one point higher";}

    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_POISON_CLOUD);
    	a.add(Character_action_code.CA_FIREBALL);
    	a.add(Character_action_code.CA_ICE_STORM);
    	return a;}
}

class Enchanter_CA extends L8_passive_CA {
    public Enchanter_CA(){
    	super();}

    String name(){
        return "Enchanter";}

    String out_of_game_description(){
    	return "It makes you more effective at casting fear and confusion spells.";}

    String describe_resolution(){
        return "Effect of fear and confusion spells is calculated as if your Subtlety was one point higher";}

    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FEAR);
    	a.add(Character_action_code.CA_CONFUSION);
    	return a;}
}

class Shaman_CA extends L8_passive_CA {
    public Shaman_CA(){
    	super();}

    String name(){
        return "Shaman";}

    String out_of_game_description(){
    	return "It allows you to cast spells more quickly.";}

    String describe_resolution(){
        return "Reduces the delays on all your spells (and other abilities) by 20%";}

    boolean priest_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FAST_CAST_FRONT_ROW);
    	a.add(Character_action_code.CA_FAST_CAST);
    	return a;}
}

class Paladin_CA extends L8_passive_CA {
    public Paladin_CA(){
    	super();}

    String name(){
        return "Paladin";}

    String out_of_game_description(){
    	return "It gives you a small bonus to aggro and melee damage.";}

    String describe_resolution(){
        return "+1 aggro, +10% base melee damage";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}

    int requires_strength(){
    	return 3;}
    int requires_valor(){
    	return 3;}
}

class Templar_CA extends L8_passive_CA {
    public Templar_CA(){
    	super();}

    String name(){
        return "Templar";}

    String out_of_game_description(){
    	return "It gives you a small bonus to melee accuracy and armor.";}

    String describe_resolution(){
        return "+1 melee accuracy, +1 armor";}

    boolean priest_ok(){
    	return true;}

    int requires_valor(){
    	return 3;}
}

class Medic_CA extends L8_passive_CA {
    public Medic_CA(){
    	super();}

    String name(){
        return "Medic";}

    String out_of_game_description(){
    	return "It makes you more effective at casting healing spells.";}

    String describe_resolution(){
        return "Effect of healing spells is calculated as if your Wisdom was one point higher";}

    boolean priest_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
}

class Padre_CA extends L8_passive_CA {
    public Padre_CA(){
    	super();}

    String name(){
        return "Padre";}

    String out_of_game_description(){
    	return "Makes the entire party resistant to fear.";}

    String describe_resolution(){
        return "Entire party is immune to fear attacks";}

    boolean priest_ok(){
    	return true;}

    int requires_valor(){
    	return 2;
    }
}

class Sneaky_CA extends Character_action {
    public Sneaky_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    String name(){
        return "Sneaky";}

    String out_of_game_description(){
    	return "It gives you a bonus to evasion.";}

    String describe_resolution(){
        return "+2 evasion";}

    boolean rogue_ok(){
    	return true;}

    int requires_cunning(){
    	return 5;}
}

class Lethal_CA extends Character_action {
    public Lethal_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    String name(){
        return "Lethal";}

    String out_of_game_description(){
    	return "It gives you a bonus to melee accuracy and damage.";}

    String describe_resolution(){
        return "+2 melee accuracy, +20% to base damage";}

    boolean rogue_ok(){
    	return true;}

    int requires_cunning(){
    	return 6;}
}

class L6_passive_CA extends Character_action {
    public L6_passive_CA(){
    	super();
    }

    boolean callable(){
        return false;
    }

    int requires_level(){
    	return 6;}
}

class Fast_CA extends L6_passive_CA {
    public Fast_CA(){
    	super();}

    String name(){
        return "Fast";}

    String out_of_game_description(){
    	return "It gives you a small bonus to your melee and missile attack speed.";}

    String describe_resolution(){
        return "+1 to melee and missile attack speed";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Inoffensive_CA extends L6_passive_CA {
    public Inoffensive_CA(){
    	super();}

    String name(){
        return "Inoffensive";}

    String out_of_game_description(){
    	return "It gives you -1 aggro, making monsters less likely to attack you.";}

    String describe_resolution(){
        return "-1 aggro";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Brutal_CA extends L6_passive_CA {
    public Brutal_CA(){
    	super();}

    String name(){
        return "Brutal";}

    String out_of_game_description(){
    	return "It adds 10% to your base damage with melee weapons.";}

    String describe_resolution(){
        return "+10% base damage with melee weapons";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_strength(){
    	return 3;}
    int requires_valor(){
    	return 3;}
    int requires_daring(){
    	return 3;}
}

class Deft_CA extends L6_passive_CA {
    public Deft_CA(){
    	super();}

    String name(){
        return "Deft";}

    String out_of_game_description(){
    	return "It gives you a small bonus to your melee and missile accuracy.";}

    String describe_resolution(){
        return "+1 to melee and missile accuracy";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    int requires_subtlety(){
    	return 3;}
    int requires_daring(){
    	return 3;}
    int requires_valor(){
    	return 3;}
    int requires_skill(){
    	return 3;}
}

class Agile_CA extends L6_passive_CA {
    public Agile_CA(){
    	super();}

    String name(){
        return "Agile";}

    String out_of_game_description(){
    	return "It gives you a small bonus to evasion.";}

    String describe_resolution(){
        return "+1 evasion";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Keen_CA extends L6_passive_CA {
    public Keen_CA(){
    	super();}

    String name(){
        return "Keen";}

    String out_of_game_description(){
    	return "It makes you gain XP slightly faster.";}

    String describe_resolution(){
        return "+10% XP gained";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Robust_CA extends L6_passive_CA {
    public Robust_CA(){
    	super();}

    String name(){
        return "Robust";}

    String out_of_game_description(){
    	return "It gives you slightly more health.";}

    String describe_resolution(){
        return "It increases your maximum health by 5";}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Armor_CA extends Character_action {
    public Armor_CA(){
    	super();
    }

    String name(){
        return "Faith Armored";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "An armor bonus applying at all times.";
    }

    String describe_resolution(){
        return "Gain +1 armor at all times";
    }

    boolean priest_ok(){
    	return true;}

    int requires_valor(){
    	return 4;}

    int requires_level(){
    	return 4;}
}

class Concentration_CA extends Character_action {
    public Concentration_CA(){
    	super();
    }

    String name(){
        return "Concentration";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "An ability allowing your character to take a small amount of damage without interrupting the spell they are casting.";
    }

   String describe_resolution(){
        return "You can take a small amount of damage without disrupting your spell-in-progress";
    }

   boolean mage_ok(){
   	return true;}

   boolean priest_ok(){
   	return true;}

   int requires_level(){
   	return 6;}
}

class Penetration_CA extends Character_action {
    public Penetration_CA(){
    	super();
    }

    String name(){
        return "Crack Shot";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "A bonus to damage with missile weapons.";
    }

    String describe_resolution(){
        return "Gain +10% base damage with missile weapons";
    }

    boolean rogue_ok(){
    	return true;}
}

class Inconspicuous_CA extends Character_action {
    public Inconspicuous_CA(){
    	super();
    }

    String name(){
        return "Inconspicuous";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "A bonus to evasion, and also makes your character less likely to draw attacks.";
    }

    String describe_resolution(){
        return "Gain +1 evasion and -1 aggro at all times";
    }

    boolean rogue_ok(){
    	return true;}
}

class Healer_CA extends Character_action {
    public Healer_CA(){
    	super();
    }

    String name(){
        return "Healer";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "With this ability, your priest regains bar by casting healing spells, rather than by killing evil enemies. Recommended if there is more than one priest in the party (otherwise they split the kill bonuses between them).";
    }

    String describe_resolution(){
        return "This priest can regain bar by casting healing spells, instead of by killing evil enemies.";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_ROSARY);
    	a.add(Character_action_code.CA_SACRIFICE);
    	return a;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
    }

class Assassin_CA extends Character_action {
    public Assassin_CA(){
    	super();
    }

    String name(){
        return "Assassin";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "With this ability, your rogue regains bar by hitting monsters in melee, rather than by getting gold. Recommended if there is more than one rogue in the party (otherwise they split the gold bonus between them).";
    }

    String describe_resolution(){
        return "This rogue can regain bar by hitting monsters with his basic melee attack, rather than by getting gold. He gets 2 bar per hit, or half the monster's level if that is higher";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_FIND_WEAKNESS);
    	a.add(Character_action_code.CA_RIPOSTE);
    	a.add(Character_action_code.CA_AMBUSH);
    	a.add(Character_action_code.CA_FLURRY);
    	return a;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_ARCHER);
    	return a;}
}

class Archer_CA extends Character_action {
    public Archer_CA(){
    	super();
    }

    String name(){
        return "Archer";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "With this ability, your rogue regains bar by shooting monsters with his basic missile attack, rather than by getting gold. Recommended if there is more than one rogue in the party (otherwise they split the gold bonus between them).";
    }

    String describe_resolution(){
        return "This rogue can regain bar by hitting monsters with his basic missile attack, rather than by getting gold. He gets 2 bar per hit, or half the monster's level if that is higher";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_ASSASSIN);
    	return a;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SNIPE);
    	a.add(Character_action_code.CA_PENETRATION);
    	return a;}

}

class Righteousness_CA extends Character_action {
    public Righteousness_CA(){
    	super();
    }

    String name(){
        return "Righteous";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_RIGHTEOUSNESS,new Effect_parameters(60));
    }

    String out_of_game_description(){
    	return "This ability makes monsters more likely to concentrate their attacks on this character, and also gives them an evasion bonus.";
    }

    String describe_resolution(){
        return "Increase Evasion and Aggro by 1 for " + (round_to_1_dp(60/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_valor(){
    	return 3;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class InsultYourMother_CA extends Character_action {
    public InsultYourMother_CA(){
    	super();
    }

    String name(){
        return "Insult Your Mother";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_INSULT,new Effect_parameters(20));
    }

    String out_of_game_description(){
    	return "When used, this ability makes enemies concentrate their attacks on the character.";
    }

    String describe_resolution(){
        return "Increase Aggro by 2 for " + (round_to_1_dp(15/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_TAUNT);
    	return a;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class FindWeakness_CA extends Character_action {
    public FindWeakness_CA(){
    	super();
    }

    String name(){
        return "Find Weakness";
    }

    int base_cost(){
        return 10;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_FIND_WEAKNESS,new Effect_parameters(20));
    }

    String out_of_game_description(){
    	return "When used, this ability helps your character to damage armored targets.";
    }

    String describe_resolution(){
        return "Your melee attacks (including Flurry, Ambush, Deathblow and so on if you have them) ignore 5 points of the victim's armor for " + (round_to_1_dp(15/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_daring(){
    	return 3;}
    int requires_skill(){
    	return 6;}

    boolean rogue_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Aggro_CA extends Character_action {
    public Aggro_CA(){
    	super();
    }

    String name(){
        return "Jehovah's Witness";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "This ability makes enemies concentrate their attacks on the character.";
    }

    String describe_resolution(){
        return "Gain +1 aggro at all times";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    int requires_valor(){
    	return 3;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_INOFFENSIVE);
    	return a;}
}

class Rosary_CA extends Character_action {
    public Rosary_CA(){
    	super();
    }

    String name(){
        return "Rosary";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "With this ability, your priest regains bar over time, rather than by killing evil enemies. Recommended if there is more than one priest in the party (otherwise they split the kill bonus between them).";
    }

    String describe_resolution(){
        return "This priest can regain bar over time, instead of by killing evil enemies.";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SACRIFICE);
    	a.add(Character_action_code.CA_HEALER);
    	return a;}
}

class Beacon_CA extends Character_action {
    public Beacon_CA(){
    	super();
    }

    String name(){
        return "Beacon";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_TAUNT3,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "When used, this ability makes enemies concentrate their attacks on the character.";
    }

    String describe_resolution(){
        return "Increase Aggro by 3 for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_constitution(){
    	return 3;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Taunt_CA extends Character_action {
    public Taunt_CA(){
    	super();
    }

    String name(){
        return "Taunt";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_TAUNT,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "When used, this ability makes enemies concentrate their attacks on the character.";
    }

    String describe_resolution(){
        return "Increase Aggro by 1 for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean warrior_ok(){
    	return true;}

    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_INOFFENSIVE);
    	return a;}
}

class DragonSlayer_CA extends Character_action {
    public DragonSlayer_CA(){
    	super();
    }

    String name(){
        return "Dragon Slayer";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "A damage bonus when attacking dragons in melee. (It adds 50% to the base damage of your weapon, before any other bonuses are applied.)";
    }

    String describe_resolution(){
        return "Character gets +50% base melee damage against dragons";
    }

    boolean warrior_ok(){
    	return false;} // TO DO - ponder this

    int requires_level(){
    	return 5;}
}

class Lob_CA extends Snipe_CA {
    public Lob_CA(){
    	super();
    }

    String name(){
        return "Lob";
    }

    String out_of_game_description(){
    	return "A missile attack against a specific enemy, used from the back row only. Not very accurate, but can be useful for disrupting enemy spellcasters.";
    }

    String describe_resolution(){
        return "Shoot a target of your choice (with -2 accuracy)";
    }

    int accuracy(){
    	return -2;}

    void make_stuff_happen(){
    	c.accuracy = c.accuracy + accuracy();
    	super.make_stuff_happen();
    	c.accuracy = c.accuracy - accuracy();
    }

    int requires_skill(){
    	return 4;}

    boolean rogue_ok(){
    	return false;}

    boolean warrior_ok(){
    	return true;}

    boolean recommended(){
    	return false;}
}

class Warrior_snipe_CA extends Lob_CA {
    public Warrior_snipe_CA(){
    	super();
    }

    String name(){
        return "Snipe";
    }

    String out_of_game_description(){
    	return "A more accurate upgrade to Lob.";
    }

    String describe_resolution(){
        return "Shoot a target of your choice (with +1 accuracy)";
    }

    int accuracy(){
    	return 1;}

    int requires_level(){
    	return 4;}

    int requires_skill(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_LOB);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_LOB);
    	return a;}
}

class Snipe_CA extends Character_action {
    public Snipe_CA(){
    	super();
    }

    String name(){
        return "Snipe";
    }

    boolean target_enemy(){
        return true;
    }

    boolean front_row_ok(){
        return false;
    }

    double delay(){
        return 0.5;
    }

    Double cooldown(){
        return 0.5;
    }

    int base_cost(){
        return 4;
    }

    void make_stuff_happen(){
        if (c.missile_hit_roll(mob_target)){
            Gamestate.add_sound(c.missile_hit_sound);
            //Gamestate.add_message(Twang!",c.image,Color.WHITE);
            mob_target.take_damage(Math.max(0,c.missile_damage_roll(mob_target)-mob_target.current_armor()));
            mob_target.has_been_shot = true;
        } else {
            Gamestate.add_sound(c.missile_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && (!m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.disruptable())
                return true;
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < (c.max_energy / 4))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && !m.front_row()){
                	if (m.code==Monster_code.MOB_UNDEAD_BOSS_PHASE12 || m.code==Monster_code.MOB_UNDEAD_BOSS_PHASE3 || m.code==Monster_code.MOB_UNDEAD_BOSS_PHASE4)
                		return true;
				}
			}
            if (c.energy < (c.max_energy / 2))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && !m.front_row()){
                    if (m.level >= c.level-1){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.disruptable()){
                mob_target = m;
                return;
            }
        }
        if (char_is_aggressive()){
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && !m.front_row()){
                    if (m.level >= c.level-1){
                    	mob_target = m;
                        return;
                    }
                }
            }
        }
    }

    String describe_reflex_condition(){
        if (char_is_aggressive()) return "a monster is trying to cast a spell that can be disrupted, or there is a dangerous target in sight";
        else return "a monster is trying to cast a spell that can be disrupted";
    }

    String out_of_game_description(){
    	return "A missile attack against a specific enemy. Can be useful for disrupting enemy spellcasters.";
    }

    String describe_resolution(){
        return "Shoot a target of your choice (with normal accuracy and damage)";
    }

    int requires_daring(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean recommended(){
    	return true;}
}

class LuckyShot_CA extends Snipe_CA {
    public LuckyShot_CA(){
    	super();
    }

    String name(){
        return "Lucky Shot";
    }

    Double cooldown(){
        return 1.0;
    }

    int base_cost(){
        return 6;
    }

    void make_stuff_happen(){
        if (c.missile_hit_roll(mob_target)){
            Gamestate.add_sound(c.missile_hit_sound);
            //Gamestate.add_message("Twang!",c.image,Color.WHITE);
            mob_target.take_damage(c.missile_damage_roll(mob_target));
            if (!mob_target.front_row())
            	mob_target.has_been_shot = true;
        } else {
            Gamestate.add_sound(c.missile_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "A snipe attack that ignores armor.";
    }

    String describe_resolution(){
        return "Shoot a target of your choice, ignoring armor";
    }

    boolean needed(){
        return false;
    }

    int requires_daring(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SNIPE);
    	return a;}

    boolean recommended(){
    	return false;}
}

class AccurateShot_CA extends Snipe_CA {
    public AccurateShot_CA(){
    	super();
    }

    String name(){
        return "Accurate Shot";
    }

    int base_cost(){
        return 6;
    }

    Double cooldown(){
        return 3.0;
    }

    void make_stuff_happen(){
        c.accuracy = c.accuracy + 6;
        if (c.missile_hit_roll(mob_target)){
            Gamestate.add_sound(c.missile_hit_sound);
            //Gamestate.add_message("Twang!",c.image,Color.WHITE);
            mob_target.take_damage(Math.max(0,c.missile_damage_roll(mob_target)-mob_target.current_armor()));
            if (!mob_target.front_row())
            	mob_target.has_been_shot = true;
        } else {
            Gamestate.add_sound(c.missile_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
        c.accuracy = c.accuracy - 6;
    }

    String out_of_game_description(){
    	return "A snipe attack with extra accuracy. Good against some spellcasters that try to deflect your missiles.";
    }

    String describe_resolution(){
        return "Shoot a target of your choice, with +6 accuracy";
    }

    boolean needed(){
        return false;
    }

    int requires_daring(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SNIPE);
    	return a;}

    boolean recommended(){
    	return false;}
}

class Just_a_scratch_CA extends LuckyEscape_CA {
    public Just_a_scratch_CA(){
    	super();
    }

    String name(){
        return "Just a Scratch";
    }

    Integer success_chance(){
    	if (c.cunning > c.constitution) return success_chance(c.cunning + 3);
    	else return success_chance(c.constitution + 3);
    }

    String out_of_game_description(){
    	return "An ability that sometimes allows you to avoid attacks causing less than 10 damage. Works better if you have high Cunning or Constitution.";
    }

    String describe_resolution(){
        return "Automatically avoid any attack doing less than 10 damage (costs 4 bar, " + (success_chance()) + "% likely to work)";
    }

    int requires_constitution(){
    	return 4;} /* or 3 cunning */

    boolean warrior_ok(){
    	return true;}
}

class LuckyEscape_CA extends Character_action {
    public LuckyEscape_CA(){
    	super();
    }

    String name(){
        return "Lucky Escape";
    }

    boolean callable(){
        return false;
    }

    Integer success_chance(){
    	if (c.cunning==0) return 30;
        return success_chance(c.cunning + 3);
    }

    String out_of_game_description(){
    	return "An ability that sometimes allows you to avoid attacks causing between 10 and 20 damage. Works better if you have high Cunning.";
    }

    String describe_resolution(){
        return "Automatically avoid any attack doing 10-20 damage (costs 12 bar, " + (success_chance()) + "% likely to work)";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Salvation_CA extends LuckyEscape_CA {
    public Salvation_CA(){
    	super();
    }

    String name(){
        return "Salvation";
    }

    Integer success_chance(){
    	if (c.wisdom==0) return 30;
        return success_chance(c.wisdom + 3);
    }

    String out_of_game_description(){
    	return "An ability that sometimes allows you to avoid attacks causing more than 20 damage. Works better if you have high Wisdom.";
    }

    String describe_resolution(){
        return "Automatically avoid any attack doing more than 20 damage (costs 24 bar, " + (success_chance()) + "% likely to work)";
    }

    int requires_wisdom(){
    	return 3;}

    boolean priest_ok(){
    	return true;}

    boolean rogue_ok(){
    	return false;}

    int requires_level(){
    	return 5;}
}

class Saving_throw_CA extends LuckyEscape_CA {
    public Saving_throw_CA(){
    	super();
    }

    String name(){
        return "Saving Throw";
    }

    Integer success_chance(){
    	if (c.daring==0) return 30;
        return success_chance(c.daring + 3);
    }

    String out_of_game_description(){
    	return "An ability that sometimes allows you to avoid attacks causing more than 20 damage. Works better if you have high Daring.";
    }

    String describe_resolution(){
        return "Automatically avoid any attack doing more than 20 damage (costs 24 bar, " + (success_chance()) + "% likely to work)";
    }

    int requires_daring(){
    	return 3;}

    int requires_level(){
    	return 5;}
}

class SteelyGaze_CA extends Character_action {
    public SteelyGaze_CA(){
    	super();
    }

    String name(){
        return "Steely Gaze";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Protects the character from all gaze attacks.";
    }

    String describe_resolution(){
        return "Makes this character immune to all gaze attacks";
    }

    boolean warrior_ok(){
    	return false;} // was true

    int requires_level(){
    	return 6;}
}

class FreeAction_CA extends Character_action {
    public FreeAction_CA(){
    	super();
    }

    String name(){
        return "Free Action";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Protects the character from all paralysis attacks.";
    }

    String describe_resolution(){
        return "Makes this character immune to all paralysis attacks";
    }

    int requires_daring(){
    	return 5;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}


class Resist_draining_CA extends Character_action {
    public Resist_draining_CA(){
    	super();
    }

    String name(){
        return "Resist Draining";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Protects the character from all energy draining attacks.";
    }

    String describe_resolution(){
        return "Makes this character immune to all energy draining attacks";
    }

    int requires_stamina(){
        return 5;}
    int requires_level(){
        return 5;}

    boolean rogue_ok(){
    	return true;}
    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}
}

class ResistFear_CA extends Character_action {
    public ResistFear_CA(){
    	super();
    }

    String name(){
        return "Resist Fear";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Protects the character from all fear attacks.";
    }

    String describe_resolution(){
        return "Makes this character immune to all fear attacks";
    }

    int requires_constitution(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}
}

class UndeadSlayer_CA extends Character_action {
    public UndeadSlayer_CA(){
    	super();
    }

    String name(){
        return "Undead Slayer";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "A damage bonus when attacking undead in melee. (It doubles the base damage of your weapon, before any other bonuses are applied.)";
    }

    String describe_resolution(){
        return "Doubles your base damage against undead";
    }

    int requires_valor(){
    	return 3;}

    boolean priest_ok(){
    	return true;}
}

class GraveRobber_CA extends UndeadSlayer_CA {
    public GraveRobber_CA(){
    	super();
    }
    String name(){
        return "Grave Robber";
    }

    boolean priest_ok(){
    	return false;}

    boolean rogue_ok(){
    	return true;}

	int requires_daring(){
		return 3;}

    int requires_level(){
    	return 4;}
}

class Magebane_CA extends Character_action {
    public Magebane_CA(){
    	super();
    }

    String name(){
        return "Mage Bane";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "An ability that helps you shoot spellcasters who have tried to protect themselves with Deflect Missiles.";
    }

    String describe_resolution(){
        return "Makes you much more likely to hit when you shoot a spellcaster who has used Deflect Missiles";
    }

    int requires_daring(){
    	return 4;}

    int requires_level(){
    	return 5;}

    boolean rogue_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SNIPE);
    	return a;}
}

class Veteran_CA extends Character_action {
    public Veteran_CA(){
    	super();
    }

    String name(){
        return "Veteran";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "This warrior will Retrench to regain bar, without being told to, if there are no enemies around.  Works much better if he has high Reflexes.";
    }

    String describe_resolution(){
        return "This warrior will Retrench to regain bar, without being told to, if there are no enemies around.";
    }

    int requires_reflexes(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_RETRENCH);
    	return a;}
}

class Rage_CA extends Character_action {
    public Rage_CA(){
    	super();
    }

    String name(){
        return "Rage";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "This warrior gains bar whenever he takes damage. Works well with Berserk.";
    }

    String describe_resolution(){
        return "This warrior gains bar whenever he takes damage.";
    }

    int requires_strength(){
    	return 4;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class WandLore_CA extends Character_action {
    public WandLore_CA(){
    	super();
    }

    String name(){
        return "Wand Lore";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Gives combat bonuses with wand attacks.";
    }

    String describe_resolution(){
        return "Gives you +1 Aim and +1 Rapidity with wand attacks";
    }

    boolean mage_ok(){
    	return true;}
}

class WandLore2_CA extends Character_action {
    public WandLore2_CA(){
    	super();
    }

    String name(){
        return "Advanced Wand Lore";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "Gives extra combat bonuses with wand attacks.";
    }

    String describe_resolution(){
        return "Gives you +2 Aim and +2 Rapidity with wand attacks";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_WAND_LORE);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_WAND_LORE);
    	return a;}
}

class Blessing_CA extends Character_action {
    public Blessing_CA(){
    	super();}

    String name(){
        return "Blessing";}

    boolean target_friend(){
        return true;}

    int base_cost(){
        return 5;}

    double duration(){
    	return 15;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        char_target.status_effects.put(Status_effect_code.EF_BLESSING,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "This ability is used to give another character a small combat bonus.";}

    String describe_resolution(){
        return "Gives the target +1 melee accuracy, +1 missile accuracy and +1 evasion for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Be_watchful_CA extends Character_action {
    public Be_watchful_CA(){
    	super();}

    String name(){
        return "Be Watchful!";}

    boolean target_friend(){
        return true;}

    int base_cost(){
        return 10;}

    double duration(){
    	return 15;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
    	char_target.status_effects.put(Status_effect_code.EF_REFLEXES,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "This ability is used to improve another character's reflexes, making them more likely to take actions without being asked.";}

    String describe_resolution(){
        return "Gives the target +2 reflexes for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 4;}
    int requires_level(){
    	return 6;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Reckless_CA extends Character_action {
    public Reckless_CA(){
    	super();}

    String name(){
        return "Reckless";}

    int base_cost(){
        return 7;}

    double duration(){
    	return 20;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_RECKLESS,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability improves the character's melee damage, but reduces their evasion.";}

    String describe_resolution(){
        return "Gives you +20% to base melee damage, but -2 evasion, for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_strength(){
    	return 4;}
    int requires_daring(){
    	return 4;}
    int requires_level(){
    	return 6;}

    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Hail_of_arrows_CA extends Character_action {
    public Hail_of_arrows_CA(){
    	super();}

    String name(){
        return "Hail of Arrows";}

    int base_cost(){
        return 5;}

    double duration(){
    	return 20;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_RAPIDITY,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability increases the character's shooting speed.";}

    String describe_resolution(){
        return "Gives you +2 missile rapidity for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_daring(){
    	return 5;}
    int requires_level(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_PENETRATION);
    	return a;}
}

class On_your_guard_CA extends Character_action {
    public On_your_guard_CA(){
    	super();}

    String name(){
        return "On Your Guard";}

    int base_cost(){
        return 10;}

    double duration(){
    	return 15;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_REFLEXES,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability improves the character's reflexes, making them more likely to take actions without being asked.";}

    String describe_resolution(){
        return "Gives you +2 reflexes for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_reflexes(){
    	return 2;}
    int requires_level(){
    	return 4;}

    boolean priest_ok(){
    	return true;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Battlecry_CA extends Character_action {
    public Battlecry_CA(){
    	super();}

    String name(){
        return "Battlecry";}

    int base_cost(){
        return 12;}

    double duration(){
    	return 20;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_BATTLECRY,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability increases your melee damage and makes monsters concentrate their attacks on you.";}

    String describe_resolution(){
        return "Gives you +20% base melee damage and +2 aggro for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_strength(){
    	return 5;}
    int requires_level(){
    	return 4;}

    boolean warrior_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Guidance_CA extends Character_action {
    public Guidance_CA(){
    	super();}

    String name(){
        return "Guidance";}

    int base_cost(){
        return 5;}

    double duration(){
    	return 5 * c.valor;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_ACCURATE,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability improves your melee accuracy. It works better if you have high Valor.";}

    String describe_resolution(){
        return "Gives you +2 melee accuracy for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_valor(){
    	return 2;}
    int requires_level(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Lift_skirts_CA extends Character_action {
    public Lift_skirts_CA(){
    	super();}

    String name(){
        return "Lift Skirts";}

    int base_cost(){
        return 5;}

    double duration(){
    	return 5 * c.valor;}

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_SPEED,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability improves your melee speed. It works better if you have high Valor.";}

    String describe_resolution(){
        return "Gives you +2 melee speed for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_valor(){
    	return 3;}
    int requires_level(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Sanctuary_CA extends Character_action {
    public Sanctuary_CA(){
    	super();}

    String name(){
        return "Sanctuary";}

    int base_cost(){
        return 8;}

    double duration(){
    	return 4.0 + c.wisdom/2.0;}

    void make_stuff_happen(){
        Gamestate.add_sound("invulnerable");
        c.status_effects.put(Status_effect_code.EF_INVULNERABLE,new Effect_parameters(duration()));
    }

    String out_of_game_description(){
    	return "When used, this ability protects you from all damage for a few seconds. It works better if you have high Wisdom.";}

    String describe_resolution(){
        return "Makes you invulnerable for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 4;}
    int requires_valor(){
    	return 5;}
    int requires_level(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Dodge_CA extends Character_action {
    public Dodge_CA(){
    	super();
    }

    String name(){
        return "Dodge";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_DODGE,new Effect_parameters(20));
    }

    String out_of_game_description(){
    	return "When used, this ability increases your evasion.";
    }

    String describe_resolution(){
        return "Increase Evasion by 2 for " + (round_to_1_dp(20/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_daring(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Meditation_CA extends Character_action {
    public Meditation_CA(){
    	super();
    }

    String name(){
        return "Meditation";
    }

    int base_cost(){
        return 4;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.status_effects.put(Status_effect_code.EF_MEDITATION,new Effect_parameters(20));
    }

    String out_of_game_description(){
    	return "When used, this ability protects the character from sleep, paralysis, stunning and fear.";
    }

    String describe_resolution(){
        return "Protect this character (only) from sleep, paralysis, stunning and fear for " + (round_to_1_dp(20/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 6;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class SlowTime_CA extends Spell_CA {
    public SlowTime_CA(){
    	super();
    }

    String name(){
        return "Slow Time";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        Gamestate.w.slow_time_until = Gamestate.w.clock + 7.0;
    }

    String out_of_game_description(){
    	return "This spell slows down time for a few seconds, allowing you to plan your next moves.";
    }

    String describe_resolution(){
        return "Slows the pace of time for a few subjective seconds, allowing you to plan your next moves";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class QuickThinking_CA extends SlowTime_CA {
    public QuickThinking_CA(){
    	super();
    }

    String out_of_game_description(){
    	return "This ability slows down time for a few seconds, allowing you to plan your next moves.";
    }

    String name(){
        return "Quick Thinking";
    }

    boolean mage_ok(){
    	return false;}

    boolean rogue_ok(){
    	return true;}

    int requires_cunning(){
    	return 3;}
 }

class BuffEV_CA extends Spell_CA {
    public BuffEV_CA(){
    	super();
    }

    String name(){
        return "Warding";
    }

    boolean target_friend(){
        return true;
    }

    int base_cost(){
        return 7;
    }

    int amount(){
        return (c.subtlety-1)/3+1;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
    	Effect_parameters effect = new Effect_parameters(20);
        effect.level = amount();
        char_target.status_effects.put(Status_effect_code.EF_EV,effect);
    }

    String out_of_game_description(){
    	return "This spell is used to increase another character's Evasion. It works better if you have very high Subtlety.";
    }

    String describe_resolution(){
        return "Increase the target's Evasion by " + (amount()) + ", for " + (round_to_1_dp(20/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_subtlety(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class ForceBrand_CA extends Spell_CA {
    public ForceBrand_CA(){
    	super();
    }

    String name(){
        return "Force Brand";
    }

    int base_cost(){
        return 4;
    }

    int amount(){
        return (c.power-1)/3+1;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        Effect_parameters effect = new Effect_parameters(30);
        effect.level = amount();
        c.status_effects.put(Status_effect_code.EF_FORCEBRAND,effect);
    }

    String out_of_game_description(){
    	return "This spell increases the wizard's melee damage. It works better if you have high Power and a good melee weapon.";
    }

    String describe_resolution(){
        return "Increase your melee damage by " + (amount()*10) + "% of your base damage, for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_power(){
    	return 3;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SHOCKWAVE);
    	return a;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Shield_CA extends Spell_CA {
    public Shield_CA(){
    	super();
    }

    String name(){
        return "Shield";
    }

    int base_cost(){
        return 6;
    }

    int amount(){
        return (c.power-1)/3+1;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        Effect_parameters effect = new Effect_parameters(30);
        effect.level = amount();
        c.status_effects.put(Status_effect_code.EF_SHIELD,effect);
    }

    String out_of_game_description(){
    	return "This spell increases the caster's armor rating. It works better if you have very high Power.";
    }

    String describe_resolution(){
        return "Increase your armor rating by " + (amount()) + ", for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_power(){
    	return 3;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SHOCKWAVE);
    	return a;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Missile_CA extends Snipe_CA {
    public Missile_CA(){
    	super();
    }

    String name(){
        return "Magic Missile";
    }

    boolean disruptable(){
    	return true;
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 5.0;
    }

    int base_cost(){
        return 5;
    }

    int hit_chance(){
        return success_chance(c.subtlety + 3);
    }

    int min_damage(){
        return 8;
    }

    int max_damage(){
        return 16;
    }

    void make_stuff_happen(){
        if (Gamestate.w.randint(1,100) <= hit_chance()){
            Gamestate.add_sound(c.missile_hit_sound);
            //Gamestate.add_message("Zap!",c.image,Color.WHITE);
            mob_target.take_damage(Math.max(0,Gamestate.w.randint(min_damage(),max_damage())-mob_target.current_armor()));
            mob_target.flash_image = "missile";
        } else {
            Gamestate.add_sound(c.missile_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    boolean needed(){
        return false;
    }

    String out_of_game_description(){
    	return "A missile attack against a specific enemy. Can be useful for disrupting enemy spellcasters. It works best if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Zap a target of your choice, with a " + ((int)Math.round(hit_chance())) + "% chance of hitting for " + (min_damage()) + "-" + (max_damage()) + " damage (before armor)";
    }

    int requires_subtlety(){
    	return 3;}

    boolean rogue_ok(){
    	return false;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SPARK);
    	return a;}

    boolean recommended(){
    	return false;}
}

class TakeCover_CA extends Character_action {
    public TakeCover_CA(){
    	super();
    }

    String name(){
        return "Take Cover!";
    }

    int base_cost(){
        return 15;
    }

    double delay(){
    	return 0.5;
    }

    Integer success_chance(){
        return success_chance(c.cunning + 3);
    }

    void make_stuff_happen(){
    	if (Gamestate.w.randint(1, 100) < success_chance()){
	        for (Character _c : Gamestate.p.chars){
	            if (_c.alive && !_c.about_to_die){
	                _c.current_stance = Stance_code.ST_TAKE_COVER;
	                _c.stance_wears_off = Gamestate.w.clock + 5;
	            }
	        }
    	} else {
    		Gamestate.add_sound("cancel");
    		Gamestate.add_message("Couldn't find cover!",c.image,Color.WHITE);
    	}
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.take_coverable())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    int reflex_level(){
        return 5;
    }

    String out_of_game_description(){
    	return "When used, this ability protects from breath weapons, lightning bolts and thrown boulders. Works better if you have high Cunning.";
    }

    String describe_resolution(){
        return "Protect party from breath weapons, lightning bolts and thrown boulders for " + (round_to_1_dp(5/Constants.TIME_SCALAR)) + " seconds. "+(success_chance())+"% likely to work";
    }

    String describe_reflex_condition(){
        return "required";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}

    boolean recommended(){
    	return true;}
}

class FindTraps_CA extends Character_action {
    public FindTraps_CA(){
    	super();
    }

    String name(){
        return "Find Traps";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        c.status_effects.put(Status_effect_code.EF_REVEAL_DANGER,new Effect_parameters(10));
    }

    String out_of_game_description(){
    	return "This ability can be used to protect yourself when you sense a trap is nearby.";
    }

    String describe_resolution(){
        return "Protect from traps for " + (round_to_1_dp(10/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean needed(){
    	for (Character c2 : Gamestate.p.chars)
    		if (c2.alive && !c2.about_to_die && c2.has_status_effect(Status_effect_code.EF_REVEAL_DANGER))
    			return false;
        return Gamestate.w.traps_here;
    }

    int reflex_level(){
        return 3;
    }

    String describe_reflex_condition(){
        return "a trap is nearby";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}

    boolean recommended(){
    	return true;}
}

class MoreGold_CA extends Character_action {
    public MoreGold_CA(){
    	super();
    }

    String name(){
        return "Looter";
    }

    boolean callable(){
        return false;
    }

    double increase(){
    	if (c.cunning==0) return 1.1;
        return (8 + c.cunning + c.cunning_for_treasure) / 10.0;
    }

    String out_of_game_description(){
    	return "This ability makes the party find more gold. It works better if you have high Cunning.";
    }

    String describe_resolution(){
        return "Find " + (int)(Math.round(100*(increase()-1))) + "% extra gold";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}
}

class MoreGems_CA extends Character_action {
    public MoreGems_CA(){
    	super();
    }

    String name(){
        return "Lapidary";
    }

    boolean callable(){
        return false;
    }

    double increase(){
    	if (c.cunning==0) return 1.2;
        return (6 + c.cunning + c.cunning_for_treasure) / 8.0;
    }

    String out_of_game_description(){
    	return "This ability makes the party find more gems. It works better if you have high Cunning.";
    }

    String describe_resolution(){
        return "Find " + (int)(Math.round(100*(increase()-1))) + "% extra gems";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_MORE_GOLD);
    	return a;}
}

class Bash_door_CA extends Character_action {
    public Bash_door_CA(){
    	super();
    }

    String name(){
        return "Bash Down Doors";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "This ability allows the warrior to smash open locked doors. Some extra heavy doors may be too hard to break.";
    }

    String describe_resolution(){
        return "Open a locked door";
    }

    int requires_strength(){
    	return 5;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Knock_CA extends Character_action {
    public Knock_CA(){
    	super();
    }

    String name(){
        return "Knock";
    }

    boolean callable(){
        return false;
    }

    String out_of_game_description(){
    	return "This ability allows the wizard to magically open locked doors.";
    }

    String describe_resolution(){
        return "Open a locked door";
    }

    int requires_subtlety(){
    	return 4;}

    boolean mage_ok(){
    	return true;}
}

class PickLocks_CA extends Character_action {
    public PickLocks_CA(){
    	super();
    }

    String name(){
        return "Pick Locks";
    }

    boolean callable(){
        return false;
    }

    double chance(){
        return success_chance(c.cunning + c.cunning_for_treasure + 4);
    }

    String out_of_game_description(){
    	return "This ability allows the rogue to open locked chests and doors. It works better if you have high Cunning.";
    }

    String describe_resolution(){
        return (chance()) + "% chance of picking locks";
    }

    int requires_cunning(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

}

class Fire_immunity_CA extends ResistFire_CA {
    public Fire_immunity_CA(){
    	super();
    }

    String name(){
        return "Fire Immunity";
    }

    int base_cost(){
        return 12;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        for (Character _c : Gamestate.p.chars)
            if (_c.alive && !_c.about_to_die)
                _c.status_effects.put(Status_effect_code.EF_IMMUNE_FIRE,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "An upgrade to Protect from Fire, providing better protection.";
    }

    String describe_resolution(){
        return "Protect party from fire, quartering damage for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 6;}

    int requires_level(){
    	return 6;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_RESIST_FIRE);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_RESIST_FIRE);
    	return a;}
}

class ResistFire_CA extends Spell_CA {
    public ResistFire_CA(){
    	super();
    }

    String name(){
        return "Protect from Fire";
    }

    int base_cost(){
        return 6;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        for (Character _c : Gamestate.p.chars)
            if (_c.alive && !_c.about_to_die)
                _c.status_effects.put(Status_effect_code.EF_RESIST_FIRE,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "This spell protects the entire party from fire.";
    }

    String describe_resolution(){
        return "Protect party from fire, halving damage for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}

    boolean recommended(){
    	return true;}
}

class Protection_from_cold_CA extends ResistFire_CA {
    public Protection_from_cold_CA(){
    	super();
    }

    String name(){
        return "Protect from Cold";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        for (Character _c : Gamestate.p.chars)
            if (_c.alive && !_c.about_to_die)
                _c.status_effects.put(Status_effect_code.EF_RESIST_COLD,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "This spell protects the entire party from cold.";
    }

    String describe_resolution(){
        return "Protect party from cold, halving damage for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean recommended(){
    	return false;}
}

class Sacrifice_CA extends Character_action {
    public Sacrifice_CA(){
    	super();
    }

    String name(){
        return "Sacrifice";
    }

    double delay(){
        return 1.0;
    }

    void make_stuff_happen(){
        int energy_gain = 0;
        if (c.energy_for_evil_kill)
            for (Double time : Gamestate.w.evil_kills)
                if (time >= Gamestate.w.clock-5)
                    energy_gain = energy_gain + 3;
        Gamestate.w.evil_kills = new ArrayList<Double>();
        if (energy_gain>0){
            c.energy = Math.min(c.max_energy,c.energy+energy_gain);;
            Gamestate.add_sound("sacrifice");
            Gamestate.add_message("The Gods are pleased!",c.image,Color.WHITE);
        } else {
            Gamestate.add_sound("cancel");
            Gamestate.add_message("The Gods are unimpressed!",c.image,Color.WHITE);
        }
    }

    boolean needed(){
    	double latest_kill = -1;
    	for (Double d : Gamestate.w.evil_kills)
    		latest_kill = Math.max(d,latest_kill);
        return c.energy_for_evil_kill && c.energy<(c.max_energy-3) && Gamestate.w.evil_kills.size()>0 && latest_kill < Gamestate.w.clock-3.5 && latest_kill >= Gamestate.w.clock-4;
    }

    int reflex_level(){
        return 3;
    }

    String out_of_game_description(){
    	return "This ability allows the priest to regain extra bar when they kill an evil enemy.";
    }

    String describe_resolution(){
        return "Gain 3 bar for each evil enemy killed in the last " + (round_to_1_dp(5/Constants.TIME_SCALAR)) + " seconds";
    }

    String describe_reflex_condition(){
        return "an evil enemy has died recently";
    }

    boolean priest_ok(){
    	return true;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_ROSARY);
    	a.add(Character_action_code.CA_HEALER);
    	return a;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}

    boolean recommended(){
    	return true;}
}

class Revitalise_CA extends Spell_CA {
    public Revitalise_CA(){
    	super();
    }

    String name(){
        return "Revitalise";
    }

    boolean target_friend(){
        return true;
    }

    int base_cost(){
        return 2;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("exhale");
        int transferred = Math.min(10,c.energy);
        transferred = Math.min(transferred,char_target.max_energy-char_target.energy);
        char_target.energy = char_target.energy + transferred;
        c.energy = c.energy - transferred;
    }

    String out_of_game_description(){
    	return "This spell transfers bar from the character to another character.";
    }

    String describe_resolution(){
        return "Transfer up to 10 points from your energy bar to another character's energy bar";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}
}

class First_aid_CA extends SelfHeal_CA {
    public First_aid_CA(){
    	super();
    }

    String name(){
        return "First Aid";
    }

    String message(){
        return "Bandages themself";
    }

    double criterion(){
        return 0.7;
    }

    int base_cost(){
        return 5;
    }

    int min_heal(){
        return 3;
    }

    int max_heal(){
        return 7;
    }

    boolean front_row_ok(){
    	return false;
    }

    Double cooldown(){
    	return 4.0;}

    String out_of_game_description(){
    	return "This ability allows the character to recover a few health points. Only usable from the back row.";
    }

    int requires_constitution(){
    	return 3;}

    boolean priest_ok(){
    	return false;}
    boolean warrior_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
    boolean mage_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}

    boolean recommended(){
    	return false;}
}

class Lay_on_hands_CA extends Spell_CA {
    public Lay_on_hands_CA(){
    	super();
    }

    String name(){
        return "Lay On Hands";
    }

    boolean target_friend(){
        return true;
    }

    boolean back_row_ok(){
        return false;
    }

    boolean friend_target_ok(Character cc){
    	if (!super.friend_target_ok(cc)) return false;
    	return cc.front_row();
    }

    int base_cost(){
        return 10;
    }

    int min_heal(){
        return 6;
    }

    int max_heal(){
        return 18;
    }

    double delay(){
    	return 1.5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("healing");
        int old_health = char_target.health;
        char_target.health = Math.min(char_target.health+Gamestate.w.randint(min_heal(),max_heal()),char_target.max_health);
        if (char_target.health > old_health){
        	char_target.flash_number = char_target.health - old_health;
        	char_target.number_starts = Gamestate.w.clock;
        	char_target.number_color = Color.GREEN;
            Gamestate.w.last_heal = Gamestate.w.clock;
            Gamestate.w.last_heal_amount = char_target.health - old_health;
    		Gamestate.w.last_heal_target = char_target;
        }
    }

    String out_of_game_description(){
    	return "This spell allows the priest to heal another character's wounds, while both are in the midst of battle.";
    }

    String describe_resolution(){
        return "Heal another front-row character for "+(min_heal())+"-"+(max_heal())+" health";
    }

    int requires_valor(){
    	return 6;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class Healing_CA extends Spell_CA {
    public Healing_CA(){
    	super();
    }

    String name(){
        return "Cure Wounds";
    }

    boolean target_friend(){
        return true;
    }

    int base_cost(){
        return 12;
    }

    int recover(){
        return 4;
    }

    int min_heal(){
    	if (c.wisdom==0) return 6;
        return ((c.wisdom+c.wisdom_for_healing+2) * 7) / 6;
    }

    int max_heal(){
    	if (c.wisdom==0) return 12;
        return ((c.wisdom+c.wisdom_for_healing+2) * 15) / 6;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("healing");
        int old_health = char_target.health;
        char_target.health = Math.min(char_target.health+Gamestate.w.randint(min_heal(),max_heal()),char_target.max_health);
        if (char_target.health > old_health){
        	char_target.flash_number = char_target.health - old_health;
        	char_target.number_starts = Gamestate.w.clock;
        	char_target.number_color = Color.GREEN;
            Gamestate.w.last_heal = Gamestate.w.clock;
            Gamestate.w.last_heal_amount = char_target.health - old_health;
    		Gamestate.w.last_heal_target = char_target;
        }
        if (c.energy_for_healing)
            c.energy = Math.min(c.max_energy,c.energy + recover());
    }

    boolean needed(){
        for (Character _c : Gamestate.p.chars)
            if (c.number!=_c.number && _c.alive && (!_c.about_to_die) && _c.health < (criterion()*_c.max_health))
                return true;
        return false;
    }

    double criterion(){
        return 0.4;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Character _c : Gamestate.p.chars){
            if (c.number!=_c.number && _c.alive && (!_c.about_to_die) && _c.health < (criterion()*_c.max_health)){
                char_target = _c;
            }
        }
    }

    String out_of_game_description(){
    	return "This important spell heals another character's wounds. It works better if you have high Wisdom.";
    }

    String describe_resolution(){
        String explanation = "Heal another character for "+(min_heal())+"-"+(max_heal())+" health";
        if (c.energy_for_healing)
            explanation = explanation + " and regain " + (recover()) + " bar";
        return explanation;
    }

    String describe_reflex_condition(){
        return "another character's health drops below " + (int)Math.round(100*criterion()) + "%";
    }

    int requires_wisdom(){
    	return 3;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}

    boolean recommended(){
    	return true;}
}

class KnitFlesh_CA extends Healing_CA {
    public KnitFlesh_CA(){
    	super();
    }

    String name(){
        return "Knit Flesh";
    }

    double criterion(){
        return 0.2;
    }

    int min_heal(){
        return ((c.subtlety+2) * 7) / 8;
    }

    int max_heal(){
        return ((c.subtlety+2) * 15) / 8;
    }
    String out_of_game_description(){
    	return "This spell allows the wizard to force-heal another character's wounds. It works better if you have high Subtlety.";
    }

    int requires_subtlety(){
    	return 3;}

    boolean priest_ok(){
    	return false;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}

class SelfHeal_CA extends Healing_CA {
    public SelfHeal_CA(){
    	super();
    }

    String name(){
        return "Heal Self";
    }

    boolean target_friend(){
        return false;
    }

    boolean needed(){
        return c.health < (criterion()*c.max_health);
    }

    int recover(){
        return 0;
    }

    void make_stuff_happen(){
    	char_target = c;
        super.make_stuff_happen();
    }

    double criterion(){
        return 0.4;
    }

    void set_reflex_target(){
        // do nothing
    }

    String out_of_game_description(){
    	return "This spell allows the priest to heal themselves. Works better if you have high Wisdom.";
    }

    String describe_resolution(){
        return "Heal yourself for "+(min_heal())+"-"+(max_heal())+" health";
    }

    String describe_reflex_condition(){
        return "your health drops below " + (100*criterion()) + "%";
    }

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
}

class SmallHeal_CA extends Healing_CA {
    public SmallHeal_CA(){
    	super();
    }

    String name(){
        return "Smaller Heal";
    }

    double delay(){
        return 1.5;
    }

    int base_cost(){
        return 5;
    }

    int recover(){
        return 2;
    }

    int min_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 3) / 6;
    }

    int max_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 7) / 6;
    }

    double criterion(){
        return 0.7;
    }

    String out_of_game_description(){
    	return "Makes your healing spells smaller and much cheaper.";
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BIG_HEAL);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
}

class BigHeal_CA extends Healing_CA {
    public BigHeal_CA(){
    	super();
    }

    String name(){
        return "Bigger Heal";
    }

    double delay(){
        return 3.0;
    }

    int base_cost(){
        return 25;
    }

    int recover(){
        return 7;
    }

    int min_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 13) / 6;
    }

    int max_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 27) / 6;
    }

    String out_of_game_description(){
    	return "Makes your healing spells bigger, though more expensive.";
    }

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SMALL_HEAL);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
}

class MassHeal_CA extends Healing_CA {
    public MassHeal_CA(){
    	super();
    }

    String name(){
        return "Mass Healing";
    }

    double delay(){
        return 3.0;
    }

    boolean target_friend(){
        return false;
    }

    int base_cost(){
        return 25;
    }

    int recover(){
        return 7;
    }

    int min_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 5) / 6;
    }

    int max_heal(){
        return ((c.wisdom+c.wisdom_for_healing+2) * 9) / 6;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("healing");
        for (Character target : Gamestate.p.chars){
            int old_health = target.health;
            target.health = Math.min(target.health+Gamestate.w.randint(min_heal(),max_heal()),target.max_health);
            if (target.health > old_health){
                target.flash_number = target.health - old_health;
                target.number_starts = Gamestate.w.clock;
                target.number_color = Color.GREEN;
            }
        }
        if (c.energy_for_healing)
            c.energy = Math.min(c.max_energy,c.energy + recover());
    }

    boolean needed(){
        double actual = 0;
        int max = 0;
        for (Character _c : Gamestate.p.chars){
            if (_c.alive && !_c.about_to_die){
                actual = actual + _c.health;
                max = max + _c.max_health;
            }
        }
        double ratio = actual/max;
        return ratio < 0.5;
    }

    void set_reflex_target(){
        // do nothing
    }

    String out_of_game_description(){
    	return "This spell heals the entire party. It works better if you have high Wisdom.";
    }

    String describe_resolution(){
        String explanation = "Heal the entire party for "+(min_heal())+"-"+(max_heal())+" health";
        if (c.energy_for_healing)
            explanation = explanation + " and regain " + (recover()) + " bar";
        return explanation;
    }

    String describe_reflex_condition(){
        return "the party drops below half its total health";
    }

    int requires_wisdom(){
    	return 5;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}
}

class CureMortalWounds_CA extends Spell_CA {
    public CureMortalWounds_CA(){
    	super();
    }

    String name(){
        return "Revive";
    }

    boolean target_friend(){
        return true;
    }

    boolean friend_target_ok(Character _c){
        if (c.number==_c.number)
            return false;
        if (!_c.alive)
            return false;
        if (_c.about_to_die)
            return true;
        return false;
    }

    int base_cost(){
        return 15;
    }

    double delay(){
        return 0.1;
    }

    void make_stuff_happen(){
        if (char_target.alive && char_target.about_to_die){
            Gamestate.add_sound("healing");
            int old_health = 0;
            char_target.health = char_target.max_health / 5;
            char_target.about_to_die = false;
            char_target.flash_number = char_target.health - old_health;
            char_target.number_starts = Gamestate.w.clock;
            char_target.number_color = Color.GREEN;
            if (c.energy_for_healing)
                c.energy = Math.min(c.max_energy,c.energy + recover());
        }
    }

    int recover(){
        return 3;
    }

    boolean ok(){
        return super.ok() && needed();
    }

    boolean needed(){
        for (Character _c : Gamestate.p.chars){
            if (c.number!=_c.number && _c.alive && _c.about_to_die){
                return true;
            }
        }
        return false;
    }

    int reflex_level(){
        return 5;
    }

    void set_reflex_target(){
    	char_target = null;
        for (Character _c : Gamestate.p.chars){
            if (c.number!=_c.number && _c.alive && _c.about_to_die){
                char_target = _c;
                return;
            }
        }
    }

    String out_of_game_description(){
    	return "This spell, if used quickly, will save another character who would otherwise be killed.";
    }

    String describe_resolution(){
        String explanation = "Save another character from death";
        if (c.energy_for_healing)
            explanation = explanation + " and regain " + (recover()) + " bar";
        explanation = explanation + ". Use this spell quickly when the skull and crossbones appear...";
        return explanation;
    }

    String describe_reflex_condition(){
        return "another character's health drops below 0";
    }

    int requires_wisdom(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 6;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_HEALING);
    	return a;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class CurePoison_CA extends Spell_CA {
    public CurePoison_CA(){
    	super();
    }

    String name(){
        return "Cure Poison";
    }

    int base_cost(){
        return 3;
    }

    boolean target_friend(){
        return true;
    }

    boolean ok(){
        return super.ok() && needed();
    }

    void make_stuff_happen(){
        Gamestate.add_sound("healing");
        if (char_target.has_status_effect(Status_effect_code.EF_POISON)){
        	char_target.status_effects.get(Status_effect_code.EF_POISON).level = 0;
        	char_target.status_effects.get(Status_effect_code.EF_POISON).lasts_until = 0;
        }
    }

    boolean needed(){
    	set_reflex_target();
    	if (char_target!=null)
            return true;
        return false;
    }

    void set_reflex_target(){
    	char_target = null;
        if (Gamestate.w.poison_cloud_until > Gamestate.w.clock)
            return;
        for (Character _c : Gamestate.p.chars){
            if (_c.alive && !_c.about_to_die && _c.has_status_effect(Status_effect_code.EF_POISON) && _c.status_effects.get(Status_effect_code.EF_POISON).level>0 && c!=_c){
                char_target = _c;
                return;
            }
        }
    }

    int reflex_level(){
        return 4;
    }

    String out_of_game_description(){
    	return "This spell cures another character from poison.";
    }

    String describe_resolution(){
        return "Cure the target of all poisoning";
    }

    String describe_reflex_condition(){
        return "a character is poisoned";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}

    boolean recommended(){
    	return true;}
}

class CureFear_CA extends CurePoison_CA {
    public CureFear_CA(){
    	super();
    }

    String name(){
        return "Cure Fear";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("healing");
        if (char_target.has_status_effect(Status_effect_code.EF_FEAR))
        	char_target.status_effects.get(Status_effect_code.EF_FEAR).lasts_until = 0;
    }

    void set_reflex_target(){
    	char_target = null;
        for (Character _c : Gamestate.p.chars){
            if (_c.alive && !_c.about_to_die && _c.has_status_effect(Status_effect_code.EF_FEAR)){
                char_target = _c;
                return;
            }
        }
    }

    String out_of_game_description(){
    	return "This spell cures another character from fear.";
    }

    String describe_resolution(){
        return "Cure the target of magical fear";
    }

    String describe_reflex_condition(){
        return "a character is afraid";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class FrontRowBuff_CA extends Character_action {
    public FrontRowBuff_CA(){
    	super();
    }

    String name(){
        return "Exhort";
    }

    int base_cost(){
        return 12;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        for (Character _c : Gamestate.p.chars)
            if (_c.alive && !_c.about_to_die && _c.front_row())
                _c.status_effects.put(Status_effect_code.EF_FRONTROWBUFF,new Effect_parameters(30));
    }

    String out_of_game_description(){
    	return "This spell gives all front-row characters a damage bonus.";
    }

    String describe_resolution(){
        return "All front row characters gain +30% base damage for " + (round_to_1_dp(30/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_valor(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class RevealDanger_CA extends Character_action {
    public RevealDanger_CA(){
    	super();
    }

    String name(){
        return "Reveal Danger";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        c.status_effects.put(Status_effect_code.EF_REVEAL_DANGER,new Effect_parameters(10));
    }

    String out_of_game_description(){
    	return "This ability can be used to protect yourself when you sense a trap is nearby.";
    }

    String describe_resolution(){
        return "Protect from traps for " + (round_to_1_dp(10/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    boolean needed(){
    	for (Character c2 : Gamestate.p.chars)
    		if (c2.alive && !c2.about_to_die && c2.has_status_effect(Status_effect_code.EF_REVEAL_DANGER))
    			return false;
        return Gamestate.w.traps_here;
    }

    int reflex_level(){
        return 3;
    }

    String describe_reflex_condition(){
        return "a trap is nearby";
    }

    boolean recommended(){
    	return true;}
}

class AllOutDefense_CA extends Character_action {
    public AllOutDefense_CA(){
    	super();
    }

    String name(){
        return "All-Out Defense";
    }

    int base_cost(){
        return 7;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("buff");
        c.current_stance = Stance_code.ST_ALL_OUT_DEFENSE;
        c.stance_wears_off = Gamestate.w.clock + 10;
    }

    String out_of_game_description(){
    	return "When used, this ability greatly increases a character's Armor and Evasion, while preventing them from attacking.";
    }

    String describe_resolution(){
        return "Increase Evasion and Armor by 3 for " + (round_to_1_dp(10/Constants.TIME_SCALAR)) + " seconds. You do not attack as normal, and if you use any ability, you lose the defensive bonuses";
    }

    boolean warrior_ok(){
    	return true;}

    int requires_skill(){
    	return 2;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class TurnUndead_CA extends Spell_CA {
    public TurnUndead_CA(){
    	super();
    }

    String name(){
        return "Turn Undead";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Begone, foul creatures of darkness!";
    }

    int base_cost(){
        return 6;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && !m.about_to_die && m.undead && m.level<=6)
                    return true;
        return false;
    }

    void make_stuff_happen(){
    	int successes = 0;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.undead){
                if (m.level<=6 && Gamestate.w.randint(1,100)<=success_chance(6 + c.wisdom/2 + c.level - 2*m.level)){
                    m.flee();
                    successes = successes + 1;
                } else {
                    Gamestate.add_message("Defies you",m.image,Color.WHITE);
                }
            }
        }
        if (successes>0)
            Gamestate.add_sound("light");
        else
            Gamestate.add_sound("cancel");
    }

    String out_of_game_description(){
    	return "This spell banishes undead enemies. It works better if you have high Wisdom.";
    }

    String describe_resolution(){
        return "Banish one or more undead monsters. They are not slain and do not yield experience or treasure, but they will trouble you no more. More effective as your level and Wisdom increase, less effective on higher level monsters, and does not work at all against the most powerful undead";
    }

    int requires_wisdom(){
    	return 3;}

    boolean priest_ok(){
    	return true;}

    boolean recommended(){
    	return true;}
}

class Animal_kinship_CA extends Spell_CA {
    public Animal_kinship_CA(){
    	super();
    }

    String name(){
        return "Animal Kinship";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Peace, my little friends!";
    }

    int base_cost(){
        return 8;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && !m.about_to_die && m.animal)
                    return true;
        return false;
    }

    void make_stuff_happen(){
    	int successes = 0;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.animal && !m.evil){
                if (Gamestate.w.randint(1,100)<=success_chance(9 + c.level - 2*m.level)){
                    m.flee();
                    successes = successes + 1;
                } else {
                    Gamestate.add_message("Defies you",m.image,Color.WHITE);
                }
            }
        }
        if (successes==0)
            Gamestate.add_sound("cancel");
    }

    String out_of_game_description(){
    	return "This is an upgrade to Befriend Animal. You can now befriend every animal on the screen.";
    }

    String describe_resolution(){
        return "Send away one or more animals. They are not slain and do not yield experience or treasure, but will trouble you no more. Evil animals are not affected";
    }

    int requires_wisdom(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BEFRIEND_ANIMAL);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_BEFRIEND_ANIMAL);
    	return a;}
}

class Befriend_animal_CA extends Spell_CA {
    public Befriend_animal_CA(){
    	super();
    }

    String name(){
        return "Befriend Animal";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Go in peace, little friend!";
    }

    int base_cost(){
        return 6;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_ok(Mob m){
        if (super.enemy_target_ok(m))
        	if (m.alive && !m.about_to_die && m.animal && !m.evil)
                return true;
        return false;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (enemy_target_ok(m))
                    return true;
        return false;
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target)){
            if (Gamestate.w.randint(1,100)<=success_chance(8 + c.level - 2*mob_target.level)){
            	mob_target.flee();
            } else {
                Gamestate.add_sound("cancel");
                Gamestate.add_message("Does not want to be your friend!",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "This spell sends away an animal that is troubling you.";
    }

    String describe_resolution(){
        return "Send away one animal. It is not slain and does not yield experience or treasure, but will trouble you no more. Evil animals are not affected";
    }

    int requires_wisdom(){
    	return 4;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Bribe_CA extends Character_action {
    public Bribe_CA(){
    	super();
    }

    String name(){
        return "Bribe";
    }

    Double cooldown(){
        return 3.0;
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 3;
    }

    boolean enemy_target_ok(Mob m){
    	return super.enemy_target_ok(m) && !m.animal && !m.undead && !m.construct && !m.never_encountered_randomly && m.level<7 && m.min_gold>0;
    }

    void make_stuff_happen(){
    	boolean success = false;
    	int amount = 0;
    	if (enemy_target_ok(mob_target)){
    		amount = Gamestate.w.randint(mob_target.min_gold,mob_target.max_gold);
    		if (Gamestate.w.collected_gold + Campaignstate.gold > amount){
    			success = true;
    		}
    	}
    	if (success){
    		Gamestate.add_sound("gold");
            Gamestate.add_message("Pays "+amount+" gold",c.image,Color.WHITE);
    		if (Gamestate.w.collected_gold > amount){
    			Gamestate.w.collected_gold = Gamestate.w.collected_gold - amount;
    		} else {
    			Campaignstate.gold = Campaignstate.gold - (amount - Gamestate.w.collected_gold);
    			Gamestate.w.collected_gold = 0;
    		}
    		mob_target.flee();
    	} else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Refuses your money!",mob_target.image,Color.WHITE);
    	}
    }

    String out_of_game_description(){
    	return "This ability allows you to pay monsters to go away!";
    }

    String describe_resolution(){
        return "Pay a monster to leave the fight. Some monsters are immune. You can use gold you have collected during the mission or gold stored at home";
    }

    boolean ok(){
        return super.ok() && (Gamestate.w.collected_gold + Campaignstate.gold > 0) && Gamestate.w.can_bribe;
    }

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    int requires_cunning(){
    	return 4;}
}

class Teleport_away_CA extends Spell_CA {
    public Teleport_away_CA(){
    	super();
    }

    String name(){
        return "Teleport Away";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Away with you!";
    }

    int base_cost(){
        return 15;
    }

    boolean target_enemy(){
        return true;
    }

    void make_stuff_happen(){
        if (!mob_target.never_encountered_randomly && Gamestate.w.randint(1,100)<=success_chance(9 + c.level - 2*mob_target.level)){
        	mob_target.flee();
        } else {
            Gamestate.add_sound("cancel");
            Gamestate.add_message("Unaffected",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This spell teleports away a single enemy. It does not always work against powerful monsters.";
    }

    String describe_resolution(){
        return "Banish one monster from your sight. It is not slain and does not yield experience or treasure, but will trouble you no more";
    }

    int requires_subtlety(){
    	return 5;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 7;}
}

class Dispel_undead_CA extends Spell_CA {
    public Dispel_undead_CA(){
    	super();
    }

    String name(){
        return "Dispel Undead";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Begone, foul creature of darkness!";
    }

    int base_cost(){
        return 12;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_ok(Mob m){
        if (super.enemy_target_ok(m))
        	if (m.alive && !m.about_to_die && m.undead)
                return true;
        return false;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (enemy_target_ok(m))
                    return true;
        return false;
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target)){
            if (Gamestate.w.randint(1,100)<=success_chance(10 + c.wisdom/2 + c.level - 2*mob_target.level)){
            	mob_target.flee();
            } else {
                Gamestate.add_sound("cancel");
                Gamestate.add_message("Defies you",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "A more powerful version of Turn Undead, used against a single high level undead enemy. It works better if you have high Wisdom.";
    }

    String describe_resolution(){
        return "Banish a single undead enemy, with high effectiveness. It is not slain and do not yield experience or treasure, but will trouble you no more. More effective as your level and Wisdom increase, and less effective on higher level monsters";
    }

    int requires_level(){
    	return 6;}

    boolean priest_ok(){
    	return true;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_TURN_UNDEAD);
    	return a;}
}

class Dispel_summons_CA extends Spell_CA {
    public Dispel_summons_CA(){
    	super();
    }

    String name(){
        return "Dispell";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Return to whence you came!";
    }

    int base_cost(){
        return 15;
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_ok(Mob m){
        if (super.enemy_target_ok(m))
        	if (m.alive && !m.about_to_die && !m.construct && (m.summoner!=null || m.from_summoning_trap))
                return true;
        return false;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (enemy_target_ok(m))
                    return true;
        return false;
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target)){
            if (Gamestate.w.randint(1,100)<=success_chance(13 + c.level - 2*mob_target.level)){
            	mob_target.flee();
            } else {
                Gamestate.add_sound("cancel");
                Gamestate.add_message("Defies you",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "This spell banishes a single monster that was summoned against you. It is more effective than Banish against high level summons.";
    }

    String describe_resolution(){
        return "Banish one summoned monster, with high effectiveness. It is not slain and does not yield experience or treasure, but will trouble you no more. Golems are not affected";
    }

    int requires_wisdom(){
    	return 5;}

    int requires_power(){
    	return 5;}

    boolean mage_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 7;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_DISPELL);
    	return a;}
}

class Dispell_CA extends Spell_CA {
    public Dispell_CA(){
    	super();
    }

    String name(){
        return "Banish";
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "Return to whence you came!";
    }

    int base_cost(){
        return 12;
    }

    boolean ok(){
        if (super.ok())
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && !m.about_to_die && !m.construct && (m.summoner!=null || m.from_summoning_trap))
                    return true;
        return false;
    }

    void make_stuff_happen(){
    	int successes = 0;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && !m.construct && (m.summoner!=null || m.from_summoning_trap)){
                if (Gamestate.w.randint(1,100)<=success_chance(9 + c.level - 2*m.level)){
                    m.flee();
                } else {
                    successes = successes + 1;
                    Gamestate.add_message("Defies you",m.image,Color.WHITE);
                }
            }
        }
        if (successes==0)
            Gamestate.add_sound("cancel");
    }

    String out_of_game_description(){
    	return "This spell banishes monsters that were summoned against you.";
    }

    String describe_resolution(){
        return "Banish one or more summoned monsters. They are not slain and do not yield experience or treasure, but they will trouble you no more. More effective as your level increases, and less effective on higher level monsters. Golems are not affected";
    }

    int requires_wisdom(){
    	return 4;}

    int requires_power(){
    	return 4;}

    boolean mage_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 7;}
}

class Disbelieve_CA extends Spell_CA {
    public Disbelieve_CA(){
    	super();
    }

    String name(){
        return "Disbelieve";
    }

    String message(){
        return "I am not taken in by these tricks!";
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
    	boolean worked = false;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.illusion){
            	m.remove();
            	worked = true;
            }
        }
        if (!worked)
    		Gamestate.add_sound("cancel");
    }

    String out_of_game_description(){
    	return "This spell makes illusionary monsters disappear in a flash.";
    }

    String describe_resolution(){
        return "Banish all the illusionary monsters on the screen";
    }

    int requires_cunning(){
    	return 4;}

    int requires_wisdom(){
    	return 5;}

    int requires_subtlety(){
    	return 5;}

    boolean mage_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class PoisonousCloud_CA extends Spell_CA {
    public PoisonousCloud_CA(){
    	super();
    }

    String name(){
        return "Poison Cloud";
    }

    String message(){
        return "'Psssssssch...'";
    }

    Double cooldown(){
        return 3.0;
    }

    int base_cost(){
        return 6;
    }

    int min_damage(){
        return ((c.power + c.power_for_mass + 2) * 8) / 5;
    }

    int max_damage(){
        return ((c.power + c.power_for_mass + 2) * 16) / 5;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("gas");
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.front_row() && !m.poison_resistant){
            	m.poisoned_until = Gamestate.w.clock + 0.5*Gamestate.w.randint(min_damage(),max_damage());
            	m.poison_period = 0.5;
                m.flash_image = "poison_cloud";
            }
        }
    }

    String out_of_game_description(){
    	return "This spell attacks all front row enemies with poison. It works better if you have high Power.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to all front row enemies. Armor is no protection but poison resistant enemies are immune";
    }

    int requires_power(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((2 * c.max_energy) / 3))
                return false;
            int count = 0;
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && (!m.about_to_die) && m.front_row() && !m.poison_resistant)
                    count = count + 1;
            if (count==3)
                return true;
        }
        return false;
    }

    String describe_reflex_condition(){
        if (char_is_aggressive()){
            return "you have plenty of energy and there are three front-row opponents before you";
        } else {
            return null;
        }
    }

    boolean recommended(){
    	return true;}
}

class Ice_storm_CA extends Spell_CA {
    public Ice_storm_CA(){
    	super();
    }

    String name(){
        return "Ice Storm";
    }

    double delay(){
        return 3.0;
    }

    String message(){
        return "'WHOOOOOoooooOOOOeeeee!'";
    }

    int base_cost(){
        return 25;
    }

    int base_damage(){
        return 2*(c.power+c.power_for_mass+2);
    }

    void make_stuff_happen(){
        Gamestate.add_sound("wind");
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.front_row() && !m.cold_resistant){
                m.flash_image = "cold";
                m.take_damage(4*base_damage());
            } else if (m.alive && !m.about_to_die && !m.front_row() && !m.cold_resistant){
                m.flash_image = "cold";
                m.take_damage(2*base_damage());
            }
        }
        boolean in_cover = false;
        for (Character c : Gamestate.p.chars){
            if (c.alive && !c.about_to_die && c.front_row()){
                if (c.current_stance==Stance_code.ST_TAKE_COVER){
                	in_cover = true;
                	c.current_stance = null;
                }
            }
        }
    	c.action_in_progress = null;
        for (Character c2 : Gamestate.p.chars){
        	if (c2.alive && !c2.about_to_die && !c2.cold_resistance){
                c2.flash_image = "cold";
                if (in_cover)
                	c2.take_damage(base_damage());
                else
                   	c2.take_damage(base_damage()/2);
           	}
        }
    }

    String out_of_game_description(){
        return "This spell does a lot of cold damage to everything on the screen - both enemies and characters. It is more effective if you have high Power.";
    }

    String describe_resolution(){
    	return "This spell does " + 4*base_damage() + " cold damage to all front row enemies, " + 2*base_damage() + " damage to all back row row enemies, and " + base_damage() + " damage to all characters. You can evade some of the damage by Taking Cover...";
    }

    int requires_power(){
    	return 4;}

    int requires_level(){
    	return 6;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Chain_lightning_CA extends Spell_CA {
    public Chain_lightning_CA(){
    	super();
    }

    String name(){
        return "Chain Lightning";
    }

    double delay(){
        return 3.0;
    }

    String message(){
        return "'ZZZAAAPPP!'";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 40;
    }

    int average_damage(){
        return ((c.power+c.power_for_bolt+2) * 50) / 7;
    }

    void make_stuff_happen(){
        if (!mob_target.lightning_resistant){
            Gamestate.add_sound("lightning_bolt");
            Gamestate.w.chain_lightning_damage = Gamestate.w.randint(average_damage()/2,(average_damage()*3)/2);
            Gamestate.w.chain_lightning_pos = mob_target.pos;
            Gamestate.w.chain_lightning_last_time = Gamestate.w.clock;
            mob_target.take_damage(Gamestate.w.chain_lightning_damage);
            mob_target.flash_image = "lightning";
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Immune to lightning!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
        return "This spell hits several targets with lightning. It is more effective if you have high Power.";
    }

    String describe_resolution(){
    	return "This spell does an average of " + average_damage() + " lightning damage to one or more targets";
    }

    int requires_power(){
    	return 4;}

    int requires_level(){
    	return 7;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Delayed_blast_CA extends Spell_CA {
    public Delayed_blast_CA(){
    	super();
    }

    String name(){
        return "Delayed Blast";
    }

    int base_cost(){
        return 30;
    }

    void make_stuff_happen(){
        Gamestate.w.blast_at = Gamestate.w.clock + 20;
    }

    String out_of_game_description(){
        return "This spell creates a fireball that goes off after a long wait.";
    }

    String describe_resolution(){
    	return "This spell does 30 fire damage to all your enemies, after a delay of " + (round_to_1_dp(20/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_power(){
    	return 4;}

    int requires_level(){
    	return 7;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Fireball_CA extends Spell_CA {
    public Fireball_CA(){
    	super();
    }

    String name(){
        return "Fireball";
    }

    double delay(){
        return 3.0;
    }

    String message(){
        return "'BOOOOMMM!'";
    }

    int base_cost(){
        return 36;
    }

    int base_damage(){
        return 4*(c.power+c.power_for_mass+2);
    }

    void make_stuff_happen(){
        Gamestate.add_sound("breath");
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && !m.fire_resistant){
                m.flash_image = "fire";
                m.take_damage(Gamestate.w.randint(base_damage()/2,(base_damage()*3)/2));
            }
        }
    }

    String out_of_game_description(){
        return "This spell does a lot of fire damage to all the monsters on the screen. It is more effective if you have high Power.";
    }

    String describe_resolution(){
    	return "This spell does an average of " + base_damage() + " fire damage to all your enemies";
    }

    int requires_power(){
    	return 4;}

    int requires_level(){
    	return 7;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Shockwave_CA extends Spell_CA {
    public Shockwave_CA(){
    	super();
    }

    String name(){
        return "Shockwave";
    }

    String message(){
        return "'KABOOM'";
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 7;
    }

    int min_damage(){
        return ((c.power+c.power_for_mass+2) * 8) / 9;
    }

    int max_damage(){
        return ((c.power+c.power_for_mass+2) * 16) / 9;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("bang");
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.front_row()){
                m.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
                m.flash_image = "lightning";
                if (m.alive && !m.about_to_die && !m.stun_resistant){
                    m.stunned = true;
                    Gamestate.add_message("Stunned",m.image,Color.WHITE);
                    double duration = Gamestate.w.randint(2,8) * (2.0 / (2 + (m.max_health / 50.0)));
                    if (m.dupe_until >= Gamestate.w.clock)
                        duration = duration * 2;
                    m.stunned_until = Gamestate.w.clock + duration;
                    m.action_in_progress = null;
                }
            }
        }
    }

    String out_of_game_description(){
    	return "This spell attacks all front row enemies and may also stun them. It works better if you have high Power. Can only be used from the front row. It is also a prerequisite for several other mage abilities that are intended to be used from the front row only.";
    }

    String describe_resolution(){
        return "Does "+(min_damage())+"-"+(max_damage())+" damage to all front row enemies, and may also stun them if they are not stun resistant. Armor is no protection. Can only be used from the front row";
    }

    int requires_power(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Curse_CA extends Spell_CA {
    public Curse_CA(){
    	super();
    }

    String name(){
        return "Curse";
    }

    String message(){
    	List<String> options = Arrays.asList("May you be eternally cast out!","The fiend take you!","A plague on you!","Foul creature of darkness!","Be damned both coming and going!");
        return options.get(Gamestate.w.randint(0,options.size()-1));
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 5;
    }

    int min_damage(){
        return 5;
    }

    int max_damage(){
        return 10;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("smite");
        if (mob_target.alive && !mob_target.about_to_die){
        	mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
            if (mob_target.alive && !mob_target.about_to_die && !mob_target.stun_resistant){
            	mob_target.stunned = true;
                Gamestate.add_message("Stunned",mob_target.image,Color.WHITE);
                double duration = Gamestate.w.randint(2,8) * (2.0 / (2 + (mob_target.max_health / 50.0)));
                if (mob_target.dupe_until >= Gamestate.w.clock)
                    duration = duration * 2;
                mob_target.stunned_until = Gamestate.w.clock + duration;
                mob_target.action_in_progress = null;
            }
        }
    }

    String out_of_game_description(){
    	return "This spell damages one of your front-row enemies, and may also stun them.";
    }

    String describe_resolution(){
        return "Does "+(min_damage())+"-"+(max_damage())+" damage to a single front-row enemy, and may also stun them if they are not stun resistant. Armor is no protection";
    }

    int requires_valor(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Mass_confusion_CA extends Spell_CA {
    public Mass_confusion_CA(){
    	super();
    }

    String name(){
        return "Mass Confusion";
    }

    int base_cost(){
        return 18;
    }

    void make_stuff_happen(){
    	boolean any_confused = false;
        for (Mob m : Gamestate.e.mobs){
        	if (m.alive && !m.about_to_die){
	            int resistance = m.level;
	            if (m.confusion_resistant)
	                resistance = resistance + 99;
	            for (Monster_action a : m.actions)
	                if (a.action_code==Monster_action_code.MA_GET_CONFUSED)
	                    resistance = resistance - 2;
	            if (m.dupe_until >= Gamestate.w.clock)
	                resistance = resistance - 3;
	            int diff = success_chance(6 + c.subtlety + c.subtlety_for_fear - resistance) - Gamestate.w.randint(1,100);
	            if (diff >= 0){
	            	any_confused = true;
	            	m.confused = true;
	                Gamestate.add_message("Confused",m.image,Color.WHITE);
	                double duration = Gamestate.w.randint(5,10);
	                if (diff >= 60){
	                    duration = duration * 2.0;
	                } else if (diff >= 30){
	                    duration = duration * 1.5;
	                }
	                m.confused_until = Gamestate.w.clock + duration;
	                m.action_in_progress = null;
	            }
        	}
        }
        if (any_confused)
	        Gamestate.add_sound("confuse");
    }

    String out_of_game_description(){
    	return "This spell tries to confuse all your enemies at once. Some enemies are immune, but some are particularly vulnerable. It works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Confuses multiple enemies. More likely to work if your Subtlety is high and the monsters are not very high-level. Some monsters are immune; others (such as the stupider giants and ogres) may be particularly vulnerable";
    }

    int requires_subtlety(){
    	return 4;}

    int requires_level(){
    	return 5;
    }

    boolean mage_ok(){
    	return true;}
}

class Riddle_CA extends Spell_CA {
    public Riddle_CA(){
    	super();
    }

    String name(){
        return "Riddle";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return true; // false;
    }

    Double cooldown(){
        return 10.0;
    }

    boolean enemy_target_ok(Mob m){
        if (super.enemy_target_ok(m))
        	if (m.alive && !m.about_to_die && m.dragon)
                return true;
        return false;
    }

    int base_cost(){
        return 6;
    }

    void make_stuff_happen(){
        if (mob_target.alive && !mob_target.about_to_die){
            int resistance = mob_target.level;
            if (mob_target.dupe_until >= Gamestate.w.clock)
                resistance = resistance - 3;
            int diff = success_chance(9 + Math.max(c.subtlety+c.subtlety_for_fear,c.cunning) - resistance) - Gamestate.w.randint(1,100);
            if (diff >= 0){
            	mob_target.confused = true;
    	        Gamestate.add_sound("confuse");
                Gamestate.add_message("It's baffled!",mob_target.image,Color.WHITE);
                double duration = Gamestate.w.randint(5,10);
                if (diff >= 60){
                    duration = duration * 2.0;
                } else if (diff >= 30){
                    duration = duration * 1.5;
                }
                mob_target.confused_until = Gamestate.w.clock + duration;
                mob_target.action_in_progress = null;
            } else {
    	        Gamestate.add_sound("cancel");
                Gamestate.add_message("It knows the answer!",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "Dragons love to play riddles, and may be distracted for a few moments by a puzzling conundrum.";
    }

    String describe_resolution(){
        return "May confuse a dragon for a few seconds, if you are lucky";
    }

    int requires_subtlety(){
    	return 6;}
    int requires_cunning(){
    	return 6;}

    boolean mage_ok(){
    	return true;}
    boolean rogue_ok(){
    	return true;}
}

class Confusion_CA extends Spell_CA {
    public Confusion_CA(){
    	super();
    }

    String name(){
        return "Confusion";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return true; // false;
    }

    int base_cost(){
        return 6;
    }

    void make_stuff_happen(){
        if (mob_target.alive && !mob_target.about_to_die){
            int resistance = mob_target.level;
            if (mob_target.confusion_resistant)
                resistance = resistance + 99;
            for (Monster_action a : mob_target.actions)
                if (a.action_code==Monster_action_code.MA_GET_CONFUSED)
                    resistance = resistance - 2;
            if (mob_target.dupe_until >= Gamestate.w.clock)
                resistance = resistance - 3;
            int diff = success_chance(6 + c.subtlety + c.subtlety_for_fear - resistance) - Gamestate.w.randint(1,100);
            if (diff >= 0){
    	        Gamestate.add_sound("confuse");
            	mob_target.confused = true;
                Gamestate.add_message("Confused",mob_target.image,Color.WHITE);
                double duration = Gamestate.w.randint(5,10);
                if (diff >= 60){
                    duration = duration * 2.0;
                } else if (diff >= 30){
                    duration = duration * 1.5;
                }
                mob_target.confused_until = Gamestate.w.clock + duration;
                mob_target.action_in_progress = null;
            } else {
        		Gamestate.add_sound("cancel");
                Gamestate.add_message("Resists!",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "This spell tries to confuse an enemy. Some enemies are immune, but some are particularly vulnerable. It works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Confuses a single enemy. More likely to work if your Subtlety is high and the monster is not very high-level. Some monsters are immune; others (such as the stupider giants and ogres) may be particularly vulnerable";
    }

    int requires_subtlety(){
    	return 3;}

    boolean mage_ok(){
    	return true;}
}

class ConfusingSpiel_CA extends Spell_CA {
    public ConfusingSpiel_CA(){
    	super();
    }

    String name(){
        return "Confusing Spiel";
    }

    String message(){
    	List<String> options = Arrays.asList("I once travelled to far Almany...","Three men walked into a tavern...","Now watch my hands carefully...","Let me spin you a tale...","You'll not top this, but...");
        return options.get(Gamestate.w.randint(0,options.size()-1));
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        if (mob_target.alive && !mob_target.about_to_die){
            if (!mob_target.confusion_resistant){
                Gamestate.add_sound("good_spell");
            	mob_target.dupe_until = Gamestate.w.clock + 30;
            } else {
        		Gamestate.add_sound("cancel");
                Gamestate.add_message("It doesn't believe your tall tale!",mob_target.image,Color.WHITE);
            }
        }
    }

    String out_of_game_description(){
    	return "When used, this ability makes an enemy especially vulnerable to your stun and confusion attacks.";
    }

    String describe_resolution(){
        return "Your Rogue tells an improbable story to a monster.  The poor dupe becomes more vulnerable to your other characters' stun and confusion attacks for the next few seconds";
    }

    int requires_cunning(){
    	return 4;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class PoisonCloud2_CA extends PoisonousCloud_CA {
    public PoisonCloud2_CA(){
    	super();
    }

    String name(){
        return "Sparkling Cloud";
    }

    int base_cost(){
        return 12;
    }

    int min_damage(){
        return ((c.power+c.power_for_mass+2) * 12) / 7;
    }

    int max_damage(){
        return ((c.power+c.power_for_mass+2) * 24) / 7;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("gas");
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && !m.about_to_die && m.front_row()){
                if (!m.lightning_resistant){
                    m.flash_image = "sparkling_cloud";
                    m.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
                } else {
                    Gamestate.add_message("Immune to lightning!",m.image,Color.WHITE);
                }
            }
        }
    }

    String out_of_game_description(){
    	return "This spell is an improved version of the basic Poison Cloud. It works better if you have high Power.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to all front row enemies. Neither armor nor poison resistance protects, but lightning resistance does";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_POISON_CLOUD);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_POISON_CLOUD);
    	return a;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((2 * c.max_energy) / 3))
                return false;
            int count = 0;
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && (!m.about_to_die) && m.front_row() && !m.lightning_resistant)
                    count = count + 1;
            if (count==3)
                return true;
        }
        return false;
    }
}

class CounterspellParalysis_CA extends Character_action {
    public CounterspellParalysis_CA(){
    	super();
    }

    String name(){
        return "Counter: Paralysis";
    }

    int base_cost(){
        return 3;
    }

    boolean disruptable(){
        return true;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_PARALYSIS;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.paralysing())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    int reflex_level(){
        return 5;
    }

    String out_of_game_description(){
    	return "This important spell protects against paralysing attacks.";
    }

    String describe_resolution(){
        return "Protects from paralysing spells and gazes for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    String describe_reflex_condition(){
        return "required";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}

    boolean recommended(){
    	return true;}
}

class Chalice_CA extends Character_action {
    public Chalice_CA(){
    	super();
    }

    String name(){
        return "Chalice";
    }

    boolean disruptable(){
        return true;
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_CHALICE;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    String out_of_game_description(){
    	return "The Chalice of Incorruptible Life is the supreme spell of white magic. It is the only protection against the Finger of Death spell.";
    }

    String describe_resolution(){
        return "Protects from the Finger of Death for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 7;}

    int requires_wisdom(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class Counter_draining_CA extends CounterspellParalysis_CA {
    public Counter_draining_CA(){
    	super();
    }

    String name(){
        return "Counter: Draining";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_DRAINING;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.draining())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against energy draining attacks.";
    }

    String describe_resolution(){
        return "Protects from draining attacks for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_wisdom(){
    	return 3;}

    int requires_subtlety(){
    	return 3;}
}

class Light_CA extends CounterspellParalysis_CA {
    public Light_CA(){
    	super();
    }

    String name(){
        return "Light";
    }

    void make_stuff_happen(){
    	Gamestate.add_sound("light");
    	c.current_stance = Stance_code.ST_COUNTER_DARKNESS;
        c.stance_wears_off = Gamestate.w.clock + 2;
        Gamestate.w.darkness = 0;
        Gamestate.w.darkness_at = 0.0;
        Gamestate.w.bright_flare = Gamestate.w.clock + 0.1;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.dark())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        if (Gamestate.w.darkness > 0) return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against darkness attacks.";
    }

    String describe_resolution(){
        return "Protects from darkness attacks for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_wisdom(){
    	return 3;}

    int requires_power(){
    	return 3;}
}

class CounterFear_CA extends CounterspellParalysis_CA {
    public CounterFear_CA(){
    	super();
    }

    String name(){
        return "Counter: Fear";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_FEAR;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.scary())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against fear attacks.";
    }

    String describe_resolution(){
        return "Protects from scary spells and gazes for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return true;}

}

class CounterSleep_CA extends CounterspellParalysis_CA {
    public CounterSleep_CA(){
    	super();
    }

    String name(){
        return "Counter: Sleep";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_SLEEP;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.sleepy())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against sleep attacks.";
    }

    String describe_resolution(){
        return "Protects from sleep-causing spells and gazes for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return true;}
}

class CounterSilence_CA extends CounterspellParalysis_CA {
    public CounterSilence_CA(){
    	super();
    }

    String name(){
        return "Counter: Silence";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_SILENCE;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.silencing())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against silence attacks.";
    }

    String describe_resolution(){
        return "Protects from silence-causing spells and gazes for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int requires_subtlety(){
    	return 3;}

    boolean recommended(){
    	return false;}
}

class ProtectTheFallen_CA extends CounterspellParalysis_CA {
    public ProtectTheFallen_CA(){
    	super();
    }

    String name(){
        return "Protect The Fallen";
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_DEATHBLOW;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.finishing())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This ability protects other characters against Deathblow attacks.";
    }

    String describe_resolution(){
        return "Protects a stunned, grappled or paralysed character from monsters with the Deathblow ability, for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_skill(){
    	return 2;}

    int requires_valor(){
    	return 3;}

    boolean mage_ok(){
    	return false;}

    boolean priest_ok(){
    	return true;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Reflection_CA extends CounterspellParalysis_CA {
    public Reflection_CA(){
    	super();
    }

    String name(){
        return "Reflection";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_BOLTS;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.action_in_progress!=null && m.action_in_progress.bolt())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This spell protects against firebolt and lightning bolt attacks.";
    }

    String describe_resolution(){
        return "Protects from firebolts and lightning bolts for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds. Ineffective against dragon breath";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    int reflex_level(){
        return 7;
    }
}

class Distraction_CA extends CounterspellParalysis_CA {
    public Distraction_CA(){
    	super();
    }

    String name(){
        return "Distraction";
    }

    Double cooldown(){
        return 20.0;
    }

    int base_cost(){
        return 10;
    }

    void make_stuff_happen(){
        c.current_stance = Stance_code.ST_COUNTER_MANY;
        c.stance_wears_off = Gamestate.w.clock + 4;
    }

    boolean needed(){
        return false;
    }

    String out_of_game_description(){
    	return "This spell can protect against many kinds of special attacks, though it is not reliable. ";
    }

    String describe_resolution(){
        return "Can protect the party from many kinds of special attacks, but is not reliable (especially against more powerful enemies). Lasts for " + (round_to_1_dp(4/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_cunning(){
    	return 5;}

    boolean mage_ok(){
    	return false;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 5;}
}

class StickyFlames_CA extends Spell_CA {
    public StickyFlames_CA(){
    	super();
    }

    String name(){
        return "Sticky Flames";
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'Pchouf!'";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 2;
    }

    double duration(){
        return 7.0;
    }

    double period(){
        return 0.5;
    }

    void make_stuff_happen(){
        if (!mob_target.fire_resistant){
        	Gamestate.add_sound("small fire");
        	mob_target.on_fire_until = Gamestate.w.clock + duration();
        	mob_target.fire_period = period();
        	mob_target.flash_image = "fire";
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Immune to fire!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This cheap spell attacks an enemy with fire, doing damage over time.";
    }

   String describe_resolution(){
        return "Set a front row target of your choice on fire. The target takes one fire damage every " + (round_to_1_dp(period()/Constants.TIME_SCALAR)) + " seconds for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds. Armor is no protection";
    }

   int requires_power(){
   	return 3;}

   boolean mage_ok(){
   	return true;}

   Action_color_code color(){
   	return Action_color_code.ACC_RED;}
}

class Eternal_flame_CA extends StickyFlames_CA {
    public Eternal_flame_CA(){
    	super();
    }

    String name(){
        return "Eternal Flame";
    }

    int base_cost(){
        return 4;
    }

    double duration(){
        return 30.0;
    }

    double period(){
        return 0.7;
    }

    String out_of_game_description(){
    	return "An upgrade to Sticky Flames, doing damage for much longer.";
    }

    int requires_level(){
    	return 4;}

    int requires_power(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_STICKY_FLAMES);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_STICKY_FLAMES);
    	return a;}
}

class Exterminate_CA extends Spell_CA {
    public Exterminate_CA(){
    	super();
    }

    String name(){
        return "Terminate";
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'Die!'";
    }

    int base_cost(){
        return 20;
    }

    void make_stuff_happen(){
    	int n_dead = 0;
    	for (Mob m : Gamestate.e.mobs){
    		if (m.alive && !m.about_to_die && m.max_health<60 && m.level<5 && !m.construct && !m.undead){
    			n_dead = n_dead + 1;
    	        m.about_to_die = true;
    	        m.die_at = Gamestate.w.clock + 1.5;
    		}
    	}
    	if (n_dead==0){
    		Gamestate.add_sound("cancel");
    	} else {
    		Gamestate.add_sound("death magic");
    	}
    	c.action_in_progress = null;
    	c.take_damage(Gamestate.w.randint(5,15));
    }

    String out_of_game_description(){
    	return "This dark spell can potentially kill every enemy on the screen. However, only weak monsters are affected. The black magic also damages the caster's own body.";
    }

    String describe_resolution(){
        return "Kill every living enemy that has less than 60 maximum health and is no more than 4th level. Take 5-15 damage yourself";
    }

    boolean mage_ok(){
    	return true;}

    int requires_power(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_DEATH_SPELL);
    	a.add(Character_action_code.CA_DEATH_TOUCH);
    	return a;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Death_touch_CA extends Death_spell_CA {
    public Death_touch_CA(){
    	super();
    }

    String name(){
        return "Touch of Death";
    }

    boolean back_row_ok(){
        return false;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 9;
    }

    String out_of_game_description(){
    	return "This dark spell, used at close range, kills an enemy instantly. Strong enemies can resist the spell. The black magic also damages the caster's own body.";
    }

    int requires_power(){
    	return 3;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_DEATH_SPELL);
    	return a;}
 }

class Death_spell_CA extends Spell_CA {
    public Death_spell_CA(){
    	super();
    }

    String name(){
        return "Death Spell";
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'Die!'";
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 20;
    }

    void make_stuff_happen(){
    	if (mob_target.alive && !mob_target.about_to_die && mob_target.max_health<=100 && mob_target.level<6 && !mob_target.construct && !mob_target.undead){
	        Gamestate.add_sound("death magic");
	        mob_target.about_to_die = true;
	        mob_target.die_at = Gamestate.w.clock + 1.5;
    	} else {
            Gamestate.add_message("Resists!",mob_target.image,Color.WHITE);
    		Gamestate.add_sound("cancel");
    	}
    	c.action_in_progress = null;
    	c.take_damage(Gamestate.w.randint(5,15));
    }

    String out_of_game_description(){
    	return "This dark spell kills an enemy instantly. Strong enemies can resist the spell. The black magic also damages the caster's own body.";
    }

    String describe_resolution(){
        return "Kill a living enemy that has no more than 100 maximum health and is no more than 6th level. Take 5-15 damage yourself";
    }

    int requires_power(){
    	return 4;}

    int requires_level(){
    	return 5;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    ArrayList<Character_action_code> prevents(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_DEATH_TOUCH);
    	return a;}
}

class ShockingGrasp_CA extends Spell_CA {
    public ShockingGrasp_CA(){
    	super();
    }

    String name(){
        return "Shocking Grasp";
    }

    double delay(){
        return 1.0;
    }

    Double cooldown(){
        return 5.0;
    }

    String message(){
        return "'ZZZAPPP!'";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    boolean back_row_ok(){
        return false;
    }

    int base_cost(){
        return 2;
    }

    int min_damage(){
        return 5;
    }

    int max_damage(){
        return 15;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("lightning_bolt");
        mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
        mob_target.flash_image = "lightning";
    }

    String out_of_game_description(){
    	return "This cheap spell attacks an enemy with lightning. It can only be used from the front row.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a front row target of your choice. Armor is no protection";
    }

    int requires_power(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class Extinguish_CA extends LightningBolt_CA {
    public Extinguish_CA(){
    	super();
    }

    String name(){
        return "Extinguish";
    }

    String message(){
        return "'Be quenched!'";
    }

    boolean enemy_target_back_row_ok(){
        return true;
    }

    double delay(){
        return 0.5;
    }

    Double cooldown(){
        return 3.0;
    }

    int base_cost(){
        return 7;
    }

    int min_damage(){
        return 10;
    }

    int max_damage(){
        return 30;
    }

    boolean ok(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && (m.fire_melee || (m.action_in_progress!=null && m.action_in_progress.fiery())))
                return super.ok();
        return false;
    }

    boolean enemy_target_ok(Mob m){
        return (m.fire_melee || (m.action_in_progress!=null && m.action_in_progress.fiery())) && super.enemy_target_ok(m);
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target)){
            mob_target.flash_image = "water";
            Gamestate.add_sound("extinguish");
            if (mob_target.fire_melee){
                if (mob_target.enrage > 0)
                	mob_target.enrage = 0;
            	mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
            }
            if (mob_target.action_in_progress!=null && mob_target.action_in_progress.fiery()){
                Gamestate.add_message("Action disrupted!",mob_target.image,Color.WHITE);
                mob_target.action_in_progress = null;
            }
        }
    }

    String out_of_game_description(){
    	return "This spell does damage to a fiery monster, and can also be used to protect against fire attacks.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a fiery monster (such as an elemental or burning ghost, but not a dragon unfortunately). Armor is no protection. Can also be used to counter a fire-based attack used by a monster (such as firebolts or dragon breath), or quench an elemental's rage";
    }

    int requires_power(){
    	return 8;}

    int requires_subtlety(){
    	return 5;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}

    ArrayList<Character_action_code> prerequisites(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> obsoletes(){
    	return new ArrayList<Character_action_code>();}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean needed(){
        return false;
    }
}

class Deconstruct_CA extends LightningBolt_CA {
    public Deconstruct_CA(){
    	super();
    }

    String name(){
        return "Demolish";
    }

    boolean enemy_target_back_row_ok(){
        return true;
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'Return to your component parts!'";
    }

    int base_cost(){
        return 15;
    }

    int min_damage(){
        return 80;
    }

    int max_damage(){
        return 120;
    }

    boolean ok(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !m.about_to_die && m.construct)
                return super.ok();
        return false;
    }

    boolean enemy_target_ok(Mob m){
        return m.construct && super.enemy_target_ok(m);
    }

    void make_stuff_happen(){
        if (enemy_target_ok(mob_target)){
            Gamestate.add_sound("deconstruct");
            mob_target.flash_image = "dismantle";
            mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
        }
    }

    String out_of_game_description(){
    	return "This spell does damage to a golem.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a golem of your choice. Armor is no protection";
    }

    int requires_power(){
    	return 8;}

    int requires_subtlety(){
    	return 4;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}

    ArrayList<Character_action_code> prerequisites(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> obsoletes(){
    	return new ArrayList<Character_action_code>();}

    boolean needed(){
        return false;
    }
}

class CleansingFlame_CA extends LightningBolt_CA {
    public CleansingFlame_CA(){
    	super();
    }

    String name(){
        return "Cleansing Flame";
    }

    Double cooldown(){
        return 20.0;
    }

    String message(){
        return "BURN, INFIDEL!";
    }

    int base_cost(){
        return 20;
    }

    int min_damage(){
        return 20;
    }

    int max_damage(){
        return 60;
    }

    void make_stuff_happen(){
        int damage = Gamestate.w.randint(min_damage(),max_damage());
        if (mob_target.fire_resistant)
            damage = damage / 4;
        mob_target.take_damage(damage);
        mob_target.flash_image = "fire";
        Gamestate.add_sound("fire_bolt");
    }

    String out_of_game_description(){
    	return "This spell damages an enemy with fire.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" fire damage to a front row target of your choice. Armor is no protection, but some monsters are fire resistant";
    }

    int requires_wisdom(){
    	return 6;}

    boolean mage_ok(){
    	return false;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> obsoletes(){
    	return new ArrayList<Character_action_code>();}

    boolean needed(){
        return false;
    }
}

class Spark_CA extends LightningBolt_CA {
    public Spark_CA(){
    	super();
    }

    String name(){
        return "Zap";
    }

    double delay(){
        return 1.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'Pow!'";
    }

    int base_cost(){
        return 5;
    }

    int min_damage(){
        return ((c.power+c.power_for_bolt+2) * 5) / 7;
    }

    int max_damage(){
        return ((c.power+c.power_for_bolt+2) * 30) / 7;
    }

    String out_of_game_description(){
    	return "This spell does a small amount of lightning damage to an enemy. A prerequisite for more powerful attacks. It works better if you have high Power.";
    }

    int requires_power(){
    	return 2;}

    boolean needed(){
        return false;
    }

    ArrayList<Character_action_code> prerequisites(){
    	return new ArrayList<Character_action_code>();}

    ArrayList<Character_action_code> obsoletes(){
    	return new ArrayList<Character_action_code>();}
}

class Frost_bolt_CA extends LightningBolt_CA {
    public Frost_bolt_CA(){
    	super();
    }

    String name(){
        return "Frost Bolt";
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'WHOOOEEE!'";
    }

    int base_cost(){
        return 14 ;
    }

    int min_damage(){
        return ((c.power+c.power_for_bolt+2) * 20) / 9;
    }

    int max_damage(){
        return ((c.power+c.power_for_bolt+2) * 40) / 9;
    }

    void make_stuff_happen(){
        if (!mob_target.cold_resistant){
            Gamestate.add_sound("ice_bolt");
            int damage = Gamestate.w.randint(min_damage(),max_damage());
            mob_target.take_damage(damage);
            mob_target.flash_image = "cold";
            if (mob_target.alive && !mob_target.about_to_die && !mob_target.stun_resistant && Gamestate.w.randint(1, 30)<=damage){
            	mob_target.stunned = true;
                double duration = (4.0 / (2 + (mob_target.max_health / 50.0)));
                mob_target.stunned_until = Gamestate.w.clock + duration;
                mob_target.action_in_progress = null;
            }
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Immune to cold!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This spell does a lot of damage to a single enemy, and can also stun it for a couple of seconds. It works better if you have high Power.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a front row target of your choice, and can also stun it for a couple of seconds. Armor is no protection. Some monsters are cold resistant and will take no damage.";
    }

    int requires_level(){
    	return 4;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((1 * c.max_energy) / 3))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && m.front_row() & !m.cold_resistant){
                    if (m.health >= 100){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row() && !m.cold_resistant){
                if (m.health >= 70){
                	mob_target = m;
                    return;
                }
            }
        }
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}
}

class Poison_bolt_CA extends LightningBolt_CA {
    public Poison_bolt_CA(){
    	super();
    }

    String name(){
        return "Poison Bolt";
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'BLUUURGH!'";
    }

    int base_cost(){
        return 12;
    }

    int min_damage(){
        return ((c.subtlety+2) * 20) / 6;
    }

    int max_damage(){
        return ((c.subtlety+2) * 40) / 6;
    }

    void make_stuff_happen(){
        if (!mob_target.poison_resistant){
            Gamestate.add_sound("gas");
            int damage = Gamestate.w.randint(min_damage(),max_damage());
        	mob_target.poisoned_until = Gamestate.w.clock + damage/2.0;
        	mob_target.poison_period = 0.5;
        	mob_target.flash_image = "poison_cloud";
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Immune to poison!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This spell poisons a single enemy, doing damage over time. It works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage over time, to a front row target of your choice. Armor is no protection. Some monsters are poison resistant and will take no damage.";
    }

    int requires_subtlety(){
    	return 3;}

    int requires_level(){
    	return 4;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((1 * c.max_energy) / 3))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && m.front_row() & !m.poison_resistant){
                    if (m.health >= 100){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row() && !m.poison_resistant){
                if (m.health >= 70){
                	mob_target = m;
                    return;
                }
            }
        }
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_POISON_CLOUD);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}
    
    boolean recommended(){
    	return false;}    
}

class Holy_light_CA extends Ray_of_light_CA {
    public Holy_light_CA(){
    	super();
    }

    String name(){
        return "Holy Light";
    }

    int base_cost(){
        return 24;
    }

    int min_damage(){
        return ((c.wisdom+2) * 20) / 5;
    }

    int max_damage(){
        return ((c.wisdom+2) * 40) / 5;
    }

    String out_of_game_description(){
    	return "An upgrade to the Ray of Light spell, doing much more damage though at a higher cost.";
    }

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_RAY_OF_LIGHT);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_RAY_OF_LIGHT);
    	return a;}
}

class Ray_of_light_CA extends LightningBolt_CA {
    public Ray_of_light_CA(){
    	super();
    }

    String name(){
        return "Ray of Light";
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'FLASH!'";
    }

    int base_cost(){
        return 15;
    }

    int min_damage(){
        return ((c.wisdom+2) * 20) / 10;
    }

    int max_damage(){
        return ((c.wisdom+2) * 40) / 10;
    }

    void make_stuff_happen(){
        if (mob_target.undead){
        	Gamestate.add_sound("light");
            mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
            mob_target.flash_image = "light";
            Gamestate.w.bright_flare = Gamestate.w.clock + 0.1;
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Not vulnerable to light!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This spell does damage to a single undead enemy. It works better if you have high Wisdom.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a front row undead target of your choice. Armor is no protection.";
    }

    int requires_wisdom(){
    	return 3;}

    boolean mage_ok(){
    	return false;}

    boolean priest_ok(){
    	return true;}

    int requires_level(){
    	return 4;}

    boolean needed(){
        return false;
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	return a;}

    boolean recommended(){
    	return false;}
}

class LightningBolt_CA extends Spell_CA {
    public LightningBolt_CA(){
    	super();
    }

    String name(){
        return "Lightning Bolt";
    }

    double delay(){
        return 3.0;
    }

    Double cooldown(){
        return 25.0;
    }

    String message(){
        return "'ZZZAAAPPP!'";
    }

    boolean target_enemy(){
        return true;
    }

    boolean enemy_target_back_row_ok(){
        return false;
    }

    int base_cost(){
        return 20;
    }

    int min_damage(){
        return ((c.power+c.power_for_bolt+2) * 35) / 7;
    }

    int max_damage(){
        return ((c.power+c.power_for_bolt+2) * 75) / 7;
    }

    void make_stuff_happen(){
        if (!mob_target.lightning_resistant){
            Gamestate.add_sound("lightning_bolt");
            mob_target.take_damage(Gamestate.w.randint(min_damage(),max_damage()));
            mob_target.flash_image = "lightning";
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("Immune to lightning!",mob_target.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This important spell does a lot of damage to a single enemy. It works better if you have high Power. It makes the basic Spark spell obsolete.";
    }

    String describe_resolution(){
        return "Do "+(min_damage())+"-"+(max_damage())+" damage to a front row target of your choice. Armor is no protection.";
    }

    int requires_power(){
    	return 3;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SPARK);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SPARK);
    	return a;}

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((1 * c.max_energy) / 3))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && m.front_row() & !m.lightning_resistant){
                    if (m.health >= 100){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row() && !m.lightning_resistant){
                if (m.health >= 70){
                	mob_target = m;
                    return;
                }
            }
        }
    }

    String describe_reflex_condition(){
        if (char_is_aggressive()){
            return "you have some energy and there is an opponent with at least 100 health before you";
        } else {
            return null;
        }
    }

    boolean recommended(){
    	return true;}
}

class Firebolt_CA extends LightningBolt_CA {
    public Firebolt_CA(){
    	super();
    }

    String name(){
        return "Firebolt";
    }

    double delay(){
        return 2.0;
    }

    Double cooldown(){
        return 10.0;
    }

    String message(){
        return "'WHOOSH!'";
    }

    int base_cost(){
        return 14;
    }

    int min_damage(){
        return ((c.power+c.power_for_bolt+2) * 20) / 7;
    }

    int max_damage(){
        return ((c.power+c.power_for_bolt+2) * 40) / 7;
    }

    String out_of_game_description(){
    	return "This spell damages an enemy with fire. It works better if you have high Power. It makes the basic 'Zap' spell obsolete.";
    }

    int requires_power(){
    	return 3;}

    int requires_level(){
    	return 4;}

    void make_stuff_happen(){
        int damage = Gamestate.w.randint(min_damage(),max_damage());
        if (mob_target.fire_resistant)
            damage = damage / 4;
        mob_target.take_damage(damage);
        mob_target.flash_image = "fire";
        Gamestate.add_sound("fire_bolt");
    }

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SPARK);
    	return a;}


    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_SPARK);
    	return a;}

    boolean needed(){
        if (char_is_aggressive()){
			for (Character c : Gamestate.p.chars)
				if (c.alive && !c.about_to_die && c.current_stance==Stance_code.ST_STEALTH)
					return false;
            if (c.energy < ((1 * c.max_energy) / 3))
                return false;
            for (Mob m : Gamestate.e.mobs){
                if (m.alive && (!m.about_to_die) && m.front_row() & !m.fire_resistant){
                    if (m.health >= 100){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row() && !m.fire_resistant){
                if (m.health >= 70){
                	mob_target = m;
                    return;
                }
            }
        }
    }
}

class Fly_CA extends Spell_CA {
    public Fly_CA(){
    	super();
    }

    int base_cost(){
        return 15;
    }

    String name(){
        return "Fly";
    }

    boolean ok(){
        if (super.ok()){
            if (!Gamestate.w.no_fly){
                for (Mob m : Gamestate.e.mobs)
                    if (m.alive && !m.about_to_die && m.no_fly)
                        return false;
                return true;
            }
        }
        return false;
    }

    void make_stuff_happen(){
    	int temp = c.energy; // mega kludge
    	c.energy = c.max_energy;
        if (ok()){
        	Gamestate.w.waiting_for_door = false;
        	Gamestate.w.waiting_for_chest_noise = false;
        	Gamestate.w.waiting_for_chest_contents = false;
        	Gamestate.w.waiting_for_some_reason = false;
            Gamestate.w.waiting_gold = 0;
            for (Mob m : Gamestate.e.mobs)
                if (m.alive && !m.about_to_die)
                    m.remove();
            c.current_stance = Stance_code.ST_FLY;
            c.stance_wears_off = -1;
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("You cannot fly now!",c.image,Color.WHITE);
        }
        c.energy = temp;
    }

    String out_of_game_description(){
    	return "This spell whisks your party away from your enemies. You alight later in the dungeon, possibly bypassing enemies or traps. But be careful, some flying enemies cannot be escaped so easily.";
    }

    String describe_resolution(){
        return "Whisks your party away from your enemies. You alight later in the dungeon, possibly bypassing enemies or traps.";
    }

    int requires_subtlety(){
    	return 6;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}

class Stealth_CA extends Character_action {
    public Stealth_CA(){
    	super();
    }

    String name(){
        return "Move Silently";
    }

    int base_cost(){
        return 13;
    }

    boolean ok(){
        return super.ok() && Gamestate.e.n_surviving_mobs()==0;
    }

    double chance(){
    	if (c.cunning==0) return 40;
        return success_chance(c.cunning + c.cunning_for_hide + 2);
    }

    void make_stuff_happen(){
        if (Gamestate.e.n_surviving_mobs()==0){
            Gamestate.add_message("You fade into the shadows...",c.image,Color.WHITE);
    		Gamestate.add_sound("sneak1");
            c.current_stance = Stance_code.ST_STEALTH;
            c.stance_wears_off = -1;
        } else {
    		Gamestate.add_sound("cancel");
            Gamestate.add_message("You cannot sneak now!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "When used, this ability helps you to evade the next group of monsters. It works better if you have high Cunning.";
    }
    String describe_resolution(){
        return "Usable when no monsters are near. " + (chance()) + "% likely to succeed. If it does, you will evade the next group of monsters to arrive. Be careful - some enemies will be able to spot you no matter how hard you try to hide.";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    boolean recommended(){
    	return true;}
}

class CloakOfShadows_CA extends Stealth_CA {
    public CloakOfShadows_CA(){
    	super();
    }

    String name(){
        return "Cloak of Shadows";
    }

    double delay(){
    	return 1.0;
    }

    String out_of_game_description(){
    	return "When used, this ability helps you to evade the next group of monsters. It works better if you have high Subtlety.";
    }

    String describe_resolution(){
        return "Usable when no monsters are near. " + (chance()) + "% likely to succeed. If it does, you will evade the next group of monsters to arrive. Be careful - some enemies will be able to spot you no matter how hard you try to hide.";
    }

    double chance(){
        return success_chance(c.subtlety + 2 + c.cunning_for_hide );
    }

    int requires_subtlety(){
    	return 4;}

    boolean rogue_ok(){
    	return false;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}
}

class Berserk_CA extends Character_action {
    public Berserk_CA(){
    	super();
    }

    String name(){
        return "Berserk";
    }

    int base_cost(){
        return 20;
    }

    boolean back_row_ok(){
        return false;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("berserk");
        c.current_stance = Stance_code.ST_BERSERK;
        c.stance_wears_off = Gamestate.w.clock + 15;
    }

    String out_of_game_description(){
    	return "When used, this ability gives you big melee bonuses and health regeneration - but you do not regenerate energy bar as normal, and you cannot use any abilities (except Cleave or Swipe if you have them).";
    }

    String describe_resolution(){
        return "Gives you +30% base damage and +2 attack speed and health regeneration - but you do not regenerate energy bar as normal, and you cannot use any abilities (except Cleave or Swipe if you have them). Lasts for " + (round_to_1_dp(15/Constants.TIME_SCALAR)) + " seconds";
    }

    int requires_strength(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    int requires_stamina(){
    	return 3;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class Ambush_CA extends Bash_CA {
    public Ambush_CA(){
    	super();
    }

    String name(){
        return "Ambush";
    }

    Double cooldown(){
        return 10.0;
    }

    void make_stuff_happen(){
        if (mob_target.seconds_since_arrived() > 2.5){
            Gamestate.add_message("Failed to ambush - too slow",c.image,Color.WHITE);
        } else if (c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("stab");
            Gamestate.add_message("STAB!",c.image,Color.WHITE);
            int armor = mob_target.current_armor();
            if (c.has_status_effect(Status_effect_code.EF_FIND_WEAKNESS))
                armor = Math.max(0,armor-5);
            mob_target.take_damage(Math.max(0,(int)Math.round(2 * c.melee_damage_roll(mob_target)))-armor);
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This ability can be used to quickly launch a damaging melee attack against a front-row enemy that has just appeared.";
    }

    String describe_resolution(){
        return "Use Ambush immediately when a new enemy appears, for a double damage attack. Both you and the enemy must be in the front row.";
    }

    int reflex_level(){
        return 5;
    }

    boolean needed(){
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && (!m.about_to_die) && m.front_row())
                if (m.seconds_since_arrived() < 1 && m.seconds_since_arrived() > 0.5 && m.max_health > c.melee_damage_roll(null))
                    return true;
        return false;
    }

    void set_reflex_target(){
    	mob_target = null;
        for (Mob m : Gamestate.e.mobs){
            if (m.alive && (!m.about_to_die) && m.front_row()){
                if (m.seconds_since_arrived() < 1){
                    mob_target = m;
                    return;
                }
            }
        }
    }

    String describe_reflex_condition(){
        return "an enemy has just arrived";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    boolean warrior_ok(){
    	return false;}

    int requires_level(){
    	return 4;}

    boolean recommended(){
    	return false;}
}

class Deadly_blade_CA extends Weaken_CA {
    public Deadly_blade_CA(){
    	super();
    }

    String name(){
        return "Deadly Blade";
    }

    int base_cost(){
        return 6;
    }

    double duration(){
        return 30.0;
    }

    double period(){
        return 0.5;
    }

    String out_of_game_description(){
    	return "An upgrade to Poisoned Blade - the poison takes much longer to wear off.";
    }

    int requires_cunning(){
    	return 4;}

    int requires_level(){
    	return 4;}

    ArrayList<Character_action_code> prerequisites(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_WEAKEN);
    	return a;}

    ArrayList<Character_action_code> obsoletes(){
    	ArrayList<Character_action_code> a = new ArrayList<Character_action_code>();
    	a.add(Character_action_code.CA_WEAKEN);
    	return a;}
}

class Weaken_CA extends Bash_CA {
    public Weaken_CA(){
    	super();
    }

    String name(){
        return "Poisoned Blade";
    }

    Double cooldown(){
        return 10.0;
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
        if (c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("stab");
            int armor = mob_target.current_armor();
            if (c.has_status_effect(Status_effect_code.EF_FIND_WEAKNESS))
                armor = Math.max(0,armor-5);
            int damage = (int)Math.round(c.melee_damage_roll(mob_target));
            if (damage > armor){
            	mob_target.take_damage(damage-armor);
                if (mob_target.alive && !mob_target.about_to_die){
                    if (!mob_target.poison_resistant){
                    	mob_target.poisoned_until = Gamestate.w.clock + duration();
                    	mob_target.poison_period = period();
                        Gamestate.add_message("STAB!",c.image,Color.WHITE);
                    } else {
                        Gamestate.add_message("Target was immune to poison...",c.image,Color.WHITE);
                    }
                }
            } else {
                Gamestate.add_sound(c.melee_miss_sound);
                Gamestate.add_message("Could not penetrate armor...",c.image,Color.WHITE);
            }
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    double duration(){
        return 7.0;
    }

    double period(){
        return 0.35;
    }

    String out_of_game_description(){
    	return "When used, this ability does poison damage over time to an enemy.";
    }

    String describe_resolution(){
        return "Choose a front row target to attack. If you hit and penetrate armor, the target is poisoned and takes one point of damage every " + (round_to_1_dp(period()/Constants.TIME_SCALAR)) + " seconds for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds. Some foes are resistant to poison...";
    }

    boolean needed(){
        return false;
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    boolean warrior_ok(){
    	return false;}
}

class BloodMagic_CA extends Spell_CA {
    public BloodMagic_CA(){
    	super();
    }

    String name(){
        return "Blood Magic";
    }

    Double cooldown(){
        return 5.0;
    }

    boolean ok(){
        return super.ok() && c.health > 12;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("bad_spell");
        c.health = c.health - 12;
        int recover = Math.min(10,c.max_energy-c.energy);
        c.energy = c.energy + recover;
    }

    String out_of_game_description(){
    	return "This ability can be used to convert your health bar into energy bar.";
    }

    String describe_resolution(){
        return "Convert 12 health to 10 bar";
    }

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}
}

class Escape_CA extends Spell_CA {
    public Escape_CA(){
    	super();
    }

    String name(){
        return "Word of Recall";
    }

    int base_cost(){
        return 5;
    }

    void make_stuff_happen(){
    	c.action_in_progress=null;
        c.flee();
    }

    String out_of_game_description(){
    	return "This spell teleports your character to a safe place, far away.";
    }

    String describe_resolution(){
        return "Transports you instantaneously to a safe place far away";
    }

    int reflex_level(){
        return 5;
    }

    boolean needed(){
        return c.health < 0.1 * c.max_health;
    }

    String describe_reflex_condition(){
        return "your health drops below 10% of maximum";
    }

    int requires_subtlety(){
    	return 4;}

    int requires_wisdom(){
    	return 5;}

    boolean priest_ok(){
    	return true;}

    boolean mage_ok(){
    	return true;}

    int requires_level(){
    	return 6;}

}

class QuickExit_CA extends Escape_CA {
    public QuickExit_CA(){
    	super();
    }

    String name(){
        return "Quick Exit";
    }

    String out_of_game_description(){
    	return "This ability allows your rogue to escape the dungeon instantly.";
    }

    String describe_resolution(){
        return "Removes you instantaneously from the dungeon.";
    }

    boolean priest_ok(){
    	return false;}

    boolean mage_ok(){
    	return false;}

    boolean rogue_ok(){
    	return true;}

    int requires_cunning(){
    	return 5;}

    int requires_level(){
    	return 6;}
}

class Vendetta_CA extends Character_action {
    public Vendetta_CA(){
    	super();
    }

    String name(){
        return "Vendetta";
    }

    boolean target_enemy(){
        return true;
    }

    int base_cost(){
        return 3;
    }

    void make_stuff_happen(){
    	mob_target.vendetta = true;
        Gamestate.add_message("Marked for death!",mob_target.image,Color.WHITE);
    }

    String out_of_game_description(){
    	return "When used, this ability makes your party concentrate their attacks on a single enemy.";
    }

    String describe_resolution(){
        return "Declare a vendetta against one of your enemies. Your party will concentrate their effects on that enemy until it is dead or fled";
    }

    int requires_cunning(){
    	return 3;}

    boolean rogue_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class StunningBlow_CA extends Bash_CA {
    public StunningBlow_CA(){
    	super();
    }

    String name(){
        return "Stunning Blow";
    }

    int base_cost(){
        return 4;
    }

    double damage_mult(){
        return 1;
    }

    boolean needed(){
        return false;
    }

    void make_stuff_happen(){
        if (c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("smite");
            //Gamestate.add_message("THUMP!",c.image,Color.WHITE);
            mob_target.take_damage(Math.max(0,(int)Math.round(damage_mult() * c.melee_damage_roll(mob_target)))-mob_target.current_armor());
            if (mob_target.alive && !mob_target.about_to_die && !mob_target.stun_resistant){
            	mob_target.stunned = true;
                Gamestate.add_message("Stunned",mob_target.image,Color.WHITE);
                double duration = Gamestate.w.randint(2,8) * (2.0 / (2 + (mob_target.max_health / 50.0)));
                if (mob_target.dupe_until >= Gamestate.w.clock)
                    duration = duration * 2;
                mob_target.stunned_until = Gamestate.w.clock + duration;
                mob_target.action_in_progress = null;
            }
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This ability allows you to stun enemies with your melee attacks.";
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for normal damage, and stun it for a few seconds (unless it is stun resistant). Big monsters will be stunned for a shorter time than little ones";
    }

    int requires_strength(){
    	return 5;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 4;}
}

class Knockback_CA extends Bash_CA {
    public Knockback_CA(){
    	super();
    }

    String name(){
        return "Knockback";
    }

    int base_cost(){
        return 4;
    }

    double damage_mult(){
        return 0.8;
    }

    boolean needed(){
        return false;
    }

    void make_stuff_happen(){
        if (c.melee_hit_roll(mob_target)){
            Gamestate.add_sound("smite");
            //Gamestate.add_message("THUMP!",c.image,Color.WHITE);
            if (mob_target.alive && !mob_target.about_to_die){
                if (!mob_target.stun_resistant){
                    mob_target.take_damage(Math.max(0,(int)Math.round(damage_mult() * c.melee_damage_roll(mob_target)))-mob_target.current_armor());
                    if (Gamestate.w.randint(1,100) <= success_chance(4 + c.strength - mob_target.max_health/50)){
                        if (Gamestate.e.n_surviving_front_mobs()==1 || Gamestate.e.last_free_back_pos()==null){
                            Position_code try_pos = null;
                        	if (mob_target.pos==Position_code.POS_M_FRONT_1){
                        		try_pos = Position_code.POS_M_BACK_1;
                            } else if (mob_target.pos==Position_code.POS_M_FRONT_2){
                            	try_pos = Position_code.POS_M_BACK_2;
                            } else if (mob_target.pos==Position_code.POS_M_FRONT_3){
                            	try_pos = Position_code.POS_M_BACK_3;
                            }
                        	Mob pushed_forward;
                        	if (Gamestate.e.get_monster_at_pos(try_pos)!=null){
                        		pushed_forward = Gamestate.e.get_monster_at_pos(try_pos);
                        	} else {
                        		pushed_forward = Gamestate.e.random_back_target(null);
                        	}
                            if (pushed_forward!=null){
                                pushed_forward.slide_from = pushed_forward.pos;
                                pushed_forward.pos = mob_target.pos;
                                pushed_forward.slide_to = mob_target.pos;
                                pushed_forward.slide_start = Gamestate.w.clock;
                                pushed_forward.slide_finish = Gamestate.w.clock + 0.1;
                            }
                        }
                        mob_target.slide_from = mob_target.pos;
                        mob_target.slide_start = Gamestate.w.clock;
                        mob_target.slide_finish = Gamestate.w.clock + 0.1;
                        if (mob_target.pos==Position_code.POS_M_FRONT_1 && Gamestate.e.get_monster_at_pos(Position_code.POS_M_BACK_1)==null){
                        	mob_target.pos=Position_code.POS_M_BACK_1;
                        } else if (mob_target.pos==Position_code.POS_M_FRONT_2 && Gamestate.e.get_monster_at_pos(Position_code.POS_M_BACK_2)==null){
                        	mob_target.pos=Position_code.POS_M_BACK_2;
                        } else if (mob_target.pos==Position_code.POS_M_FRONT_3 && Gamestate.e.get_monster_at_pos(Position_code.POS_M_BACK_3)==null){
                        	mob_target.pos=Position_code.POS_M_BACK_3;
                        } else {
                        	mob_target.pos = Gamestate.e.last_free_back_pos();
                        }
                    	mob_target.slide_to = mob_target.pos;
                    	mob_target.move_to_front_at = Gamestate.w.clock + 5.0;
                    } else {
                        Gamestate.add_message("Stands fast",mob_target.image,Color.WHITE);
                    }
                } else {
                    Gamestate.add_message("Immune to knockback",mob_target.image,Color.WHITE);
                }
            }
        } else {
            Gamestate.add_sound(c.melee_miss_sound);
            Gamestate.add_message("Missed!",c.image,Color.WHITE);
        }
    }

    String out_of_game_description(){
    	return "This ability allows you to push enemies into the back row with your melee attacks. It works better if you have high Strength.";
    }

    String describe_resolution(){
        return "Attack a front row target of your choice for normal damage, and push it back into the back row. More likely to work if your Strength is high and the monster is small. Stun resistant foes are immune";
    }

    int requires_strength(){
    	return 3;}

    boolean warrior_ok(){
    	return true;}

    int requires_level(){
    	return 5;}

    boolean recommended(){
    	return false;}
}

class Potion_CA extends Character_action {
    public Potion_CA(int n_potions){
    	super();
    	limited_uses = n_potions;
    }

    double delay(){
        return 2.0;
    }

    int reflex_level(){
        return 2;
    }

    boolean warrior_ok(){
    	return true;}

    boolean priest_ok(){
    	return true;}

    boolean rogue_ok(){
    	return true;}

    boolean mage_ok(){
    	return true;}

    boolean never_learnable(){
    	return true;
    }
  }

class PotBalm_CA extends Potion_CA {
    public PotBalm_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Healing Balm";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="balm";
        c.flash_long=true;
        c.n_balm_remaining = 30;
        c.next_balm_at = Gamestate.w.clock + 0.7;
        if (c.has_status_effect(Status_effect_code.EF_POISON)){
            c.status_effects.get(Status_effect_code.EF_POISON).level = 0;
            c.status_effects.get(Status_effect_code.EF_POISON).lasts_until = 0;
        }
        if (c.has_status_effect(Status_effect_code.EF_FEAR))
            c.status_effects.get(Status_effect_code.EF_FEAR).lasts_until = 0;
    }

    double delay(){
        return 1.0;
    }

    String out_of_game_description(){
    	return "This is the best healing potion, but it takes some time to have its full effect. It also cures fear and poison.";
    }

    String describe_resolution(){
        return "Heals 30 points of damage over " + (round_to_1_dp(30*0.7/Constants.TIME_SCALAR)) + " seconds. Also cures fear and poison";
    }

    Integer gold_cost(){
    	return 500;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class PotPhiltre_CA extends Potion_CA {
    public PotPhiltre_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Magic Philtre";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="philtre";
        c.flash_long=true;
        double this_duration = duration();
        c.status_effects.put(Status_effect_code.EF_RESIST_FIRE,new Effect_parameters(this_duration));
        c.status_effects.put(Status_effect_code.EF_RESIST_COLD,new Effect_parameters(this_duration));
        c.status_effects.put(Status_effect_code.EF_RESIST_POISON,new Effect_parameters(this_duration));
    }

    double delay(){
        return 1.0;
    }

    double duration(){
        return 60.0;
    }

    String out_of_game_description(){
    	return "This potion protects the drinker from fire, cold and poison, and lasts for a long time.";
    }

    String describe_resolution(){
        return "Makes the character resistant to fire, cold and poison, for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    Integer gold_cost(){
    	return 250;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class PotInvulnerability_CA extends Potion_CA {
    public PotInvulnerability_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Protection Potion";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="white";
        c.flash_long=true;
        c.status_effects.put(Status_effect_code.EF_INVULNERABLE,new Effect_parameters(duration()));
    }

    double delay(){
        return 1.0;
    }

    double duration(){
        return 7.0;
    }

    String out_of_game_description(){
    	return "This potion protects the drinker from damage for a few seconds.";
    }

    String describe_resolution(){
        return "Makes the character immune to physical damage for " + (round_to_1_dp(duration()/Constants.TIME_SCALAR)) + " seconds";
    }

    Integer gold_cost(){
    	return 50;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREY;}
}

class PotBerserk_CA extends Potion_CA {
    public PotBerserk_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Potion of Rage";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("berserk");
        c.flash_image="berserk";
        c.flash_long=true;
        c.current_stance = Stance_code.ST_BERSERK;
        c.stance_wears_off = Gamestate.w.clock + 15;
    }

    String out_of_game_description(){
    	return "This potion sends your character berserk, giving them melee bonuses - but the character does not regenerate energy bar as normal, and cannot use any abilities (except Cleave or Swipe if they have them).";
    }

    String describe_resolution(){
        return "Gives you +30% base damage and +2 attack speed and health regeneration - but you do not regenerate energy bar as normal, and cannot use any abilities (except Cleave or Swipe if you have them). Lasts for " + (round_to_1_dp(15/Constants.TIME_SCALAR)) + " seconds";
    }

    boolean mage_ok(){
    	return false;
    }

    boolean priest_ok(){
    	return false;
    }

    boolean rogue_ok(){
    	return false;
    }

    Integer gold_cost(){
    	return 20;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class PotCourage_CA extends Potion_CA {
    public PotCourage_CA(int n_potions){
    	super(n_potions);
    }
    String name(){
        return "Flask of Brandy";
    }

    boolean needed(){
        if (c.alive && !c.about_to_die && c.has_status_effect(Status_effect_code.EF_FEAR)){
            return true;
        } else {
            return false;
        }
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="brandy";
        c.flash_long=true;
        if (c.has_status_effect(Status_effect_code.EF_FEAR))
            c.status_effects.get(Status_effect_code.EF_FEAR).lasts_until = 0;
    }

    String out_of_game_description(){
    	return "Drinking this strong spirit will drive off any fear.";
    }

    String describe_resolution(){
        return "Drink this down if you are afflicted by fear, it will give you courage";
    }

    String describe_reflex_condition(){
        return "you are afraid";
    }

    Integer gold_cost(){
    	return 5;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class PotFireresist_CA extends Potion_CA {
    public PotFireresist_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Potion of Chill";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="cool";
        c.flash_long=true;
        c.status_effects.put(Status_effect_code.EF_RESIST_FIRE,new Effect_parameters(40));
    }

    boolean needed(){
        if (c.has_status_effect(Status_effect_code.EF_RESIST_FIRE))
            return false;
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.fiery())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This potion protects the drinker from fire.";
    }

    String describe_resolution(){
        return "Protect yourself from fire, halving damage for " + (round_to_1_dp(40/Constants.TIME_SCALAR)) + " seconds";
    }

    String describe_reflex_condition(){
        return "a monster is about to use a powerful fire attack against you";
    }

    Integer gold_cost(){
    	return 20;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class PotColdresist_CA extends Potion_CA {
    public PotColdresist_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Warmth Potion";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="warmth";
        c.flash_long=true;
        c.status_effects.put(Status_effect_code.EF_RESIST_COLD,new Effect_parameters(40));
    }

    boolean needed(){
        if (c.has_status_effect(Status_effect_code.EF_RESIST_COLD))
            return false;
        for (Mob m : Gamestate.e.mobs)
            if (m.alive && !(m.about_to_die) && m.action_in_progress!=null && m.action_in_progress.freezy())
                if (m.action_fires <= Gamestate.w.clock + 0.5)
                    return true;
        return false;
    }

    String out_of_game_description(){
    	return "This potion protects the drinker from cold.";
    }

    String describe_resolution(){
        return "Protect yourself from cold, halving damage for " + (round_to_1_dp(40/Constants.TIME_SCALAR)) + " seconds";
    }

    String describe_reflex_condition(){
        return "a monster is about to use a powerful cold attack against you";
    }

    Integer gold_cost(){
    	return 20;}

    Action_color_code color(){
    	return Action_color_code.ACC_YELLOW;}
}

class PotBoom_CA extends Potion_CA {
    public PotBoom_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Exploding Flask";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="boom_flask";
        c.flash_long=true;
        Gamestate.w.boom_at = Gamestate.w.clock + 1;
    }

    String out_of_game_description(){
    	return "This potion is an alchemical mistake, but it can also be used as a throwing weapon.";
    }

    String describe_resolution(){
        return "Explodes when you throw it at an enemy (or occasionally when you don't...)";
    }

    Integer gold_cost(){
    	return 30;}

    boolean priest_ok(){
    	return false;
    }

    boolean rogue_ok(){
    	return false;
    }

    boolean warrior_ok(){
    	return false;
    }

    Action_color_code color(){
    	return Action_color_code.ACC_RED;}
}

class PotAntidote_CA extends Potion_CA {
    public PotAntidote_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Antidote";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image="antidote";
        c.flash_long=true;
        if (c.has_status_effect(Status_effect_code.EF_POISON)){
            c.status_effects.get(Status_effect_code.EF_POISON).level = 0;
            c.status_effects.get(Status_effect_code.EF_POISON).lasts_until = 0;
        }
    }

    boolean needed(){
        if (c.alive && !c.about_to_die && c.has_status_effect(Status_effect_code.EF_POISON) && c.status_effects.get(Status_effect_code.EF_POISON).level>0){
            if (Gamestate.w.poison_cloud_until<0)
                return true;
            if (Gamestate.w.poison_cloud_until < Gamestate.w.clock)
                return true;
            if (!c.front_row())
                return true;
        }
        return false;
    }

    String out_of_game_description(){
    	return "This potion cures poison.";
    }

    String describe_resolution(){
        return "Cure poison";
    }

    String describe_reflex_condition(){
        return "you are poisoned";
    }

    Integer gold_cost(){
    	return 10;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class PotMedheal_CA extends Potion_CA {
    public PotMedheal_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Health Potion";
    }

    double trigger_level(){
        return 0.3;
    }

    int amount(){
        return 10;
    }

    String image(){
    	return "medheal";
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image=image();
        c.flash_long=true;
        int old_health = c.health;
        c.health = Math.min(c.health+amount(),c.max_health);
        if (c.health > old_health){
            c.flash_number = c.health - old_health;
            c.number_starts = Gamestate.w.clock;
            c.number_color = Color.GREEN;
        }
    }

    boolean needed(){
        return c.health < (trigger_level() * c.max_health);
    }

    String out_of_game_description(){
    	return "This potion heals 10 health.";
    }

    String describe_resolution(){
        return "Regain " + (amount()) + " health";
    }

    String describe_reflex_condition(){
        return "you have less than " + 100*trigger_level() + "% health";
    }

    Integer gold_cost(){
    	return 25;}

    Action_color_code color(){
    	return Action_color_code.ACC_GREEN;}
}

class PotPercentheal_CA extends PotMedheal_CA {
    public PotPercentheal_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Vitality Potion";
    }

    double trigger_level(){
        return 0.4;
    }

    String out_of_game_description(){
    	return "This potion heals 20% of your maximum health. Good for high level characters with high health.";
    }

    int amount(){
        return (int)(Math.floor(c.max_health*0.20));
    }

    Integer gold_cost(){
    	return 50;}

    String image(){
    	return "percentheal";
    }
}

class PotSmallheal_CA extends PotMedheal_CA {
    public PotSmallheal_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Tonic";
    }

    double trigger_level(){
        return 0.5;
    }

    int amount(){
        return 6;
    }

    String out_of_game_description(){
    	return "This potion heals 6 health.";
    }

    Integer gold_cost(){
    	return 10;}

    String image(){
    	return "smallheal";
    }
}

class PotBigheal_CA extends PotMedheal_CA {
    public PotBigheal_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Elixir";
    }

    double trigger_level(){
        return 0.4;
    }

    int amount(){
        return 15;
    }

    String out_of_game_description(){
    	return "This potion heals 15 health.";
    }

    Integer gold_cost(){
    	return 100;}

    String image(){
    	return "bigheal";
    }
}

class PotBarmage_CA extends Potion_CA {
    public PotBarmage_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Mana Potion";
    }

    double trigger_level(){
        return 0.3;
    }

    int amount(){
        return 10;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image=image();
        c.flash_long=true;
        int regained = Math.min(amount(), c.max_energy - c.energy);
        c.energy = c.energy + regained;
    }

    boolean needed(){
        if (c.energy < (trigger_level() * c.max_energy)){
            return true;
        } else {
            return false;
        }
    }

    String describe_resolution(){
        return "Regain " + (amount()) + " bar";
    }

    String describe_reflex_condition(){
        return "you have less than " + 100*trigger_level() + "% bar";
    }

    String out_of_game_description(){
    	return "Only usable by a wizard, this potion restores 10 bar.";
    }

    boolean priest_ok(){
    	return false;
    }

    boolean rogue_ok(){
    	return false;
    }

    boolean warrior_ok(){
    	return false;
    }

    Integer gold_cost(){
    	return 25;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}

    String image(){
    	return "bar";
    }
}

class PotBar_CA extends Potion_CA {
    public PotBar_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Energy Potion";
    }

    double trigger_level(){
        return 0.3;
    }

    int amount(){
        return 15;
    }

    void make_stuff_happen(){
        Gamestate.add_sound("potion");
        c.flash_image=image();
        c.flash_long=true;
        int regained = Math.min(amount(), c.max_energy - c.energy);
        c.energy = c.energy + regained;
    }

    boolean needed(){
        if (c.energy < (trigger_level() * c.max_energy)){
            return true;
        } else {
            return false;
        }
    }

    String describe_resolution(){
        return "Regain " + (amount()) + " bar";
    }

    String describe_reflex_condition(){
        return "you have less than " + 100*trigger_level() + "% bar";
    }

    String out_of_game_description(){
    	return "This potion restores 15 bar.";
    }

    Integer gold_cost(){
    	return 150;}

    Action_color_code color(){
    	return Action_color_code.ACC_BLUE;}

    String image(){
    	return "bigbar";
    }
}

class PotBarrogue_CA extends PotBarmage_CA {
    public PotBarrogue_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Flask of Wine";
    }

    double trigger_level(){
        return 0.3;
    }

    int amount(){
        return 10;
    }

    String out_of_game_description(){
    	return "A rogue can toss down this fine vintage to restore 10 bar.";
    }

    boolean priest_ok(){
    	return false;
    }

    boolean mage_ok(){
    	return false;
    }

    boolean warrior_ok(){
    	return false;
    }

    boolean rogue_ok(){
    	return true;
    }

    Integer gold_cost(){
    	return 25;}

    String image(){
    	return "wine";
    }
}

class PotBarpriest_CA extends PotBarmage_CA {
    public PotBarpriest_CA(int n_potions){
    	super(n_potions);
    }

    String name(){
        return "Blessed Potion";
    }

    double trigger_level(){
        return 0.3;
    }

    int amount(){
        return 10;
    }

    String out_of_game_description(){
    	return "Only usable by a priest, this potion restores 10 bar.";
    }

    boolean mage_ok(){
    	return false;
    }

    boolean rogue_ok(){
    	return false;
    }

    boolean warrior_ok(){
    	return false;
    }
    boolean priest_ok(){
    	return true;
    }

    Integer gold_cost(){
    	return 25;}

    String image(){
    	return "blessed";
    }
}

